<?php

namespace App\Http\Controllers\api;

use Exception;
use Carbon\Carbon;
use App\Models\Application\Loan;
use Illuminate\Support\Facades\DB;
use App\Http\Controllers\Controller;
use App\Http\Requests\CommissionRequest;
use App\Models\Application\Commission;
use App\Models\Bussiness\Collaborator;

class CommissionController extends Controller
{
    private $MESSAGES = [
        'INDEX' => 'WARNING.COMMISSION_INDEX',
        'STORE' => 'WARNING.COMMISSION_STORE',
        'DUPLICATED' => 'WARNING.COMMISSION_DUPLICATED',
        'LOAN' => 'WARNING.COMMISSION_LOAN',
        'COLLABORATOR' => 'WARNING.COMMISSION_COLLABORATOR',
        'STATUS' => 'WARNING.COMMISSION_STATUS',
        'VISIBLE' => 'WARNING.COMMISSION_VISIBLE',
        'DESTYOY' => 'WARNING.COMMISSION_DESTYOY',
        'PAY' => 'WARNING.COMMISSION_PAY',
        'LOAN-LIST' => 'WARNING.COMMISSION_LOAN_LIST',
    ];

    public function __construct()
    {
        $this->CHANNEL = 'commissions_errors';
    }

    public function index(CommissionRequest $request)
    {
        try {
            $isSystemAdministrator = $this->hasSystemAdministrator($request->fk_office);

            $commissions = Commission::with(['collaborator' => function ($collaborator) {
                $collaborator->with(['position'])->select('id', DB::raw("CONCAT(firstname, ' ', lastname, ' ', secondlastname) as fullname"), 'fk_position');
            }, 'loan' => function ($loan) {
                $loan->with(['client'])->select('id', 'duration', 'loandate', 'loanenddate', 'loanamount', 'weeklypayment', 'fk_client');
            },  'user_creator', 'user_updater'])
                ->whereHas('collaborator', function ($collaborator) use ($request) {
                    $collaborator->where([
                        ['fk_site', $request->fk_site],
                        ['fk_office', $request->fk_office],
                        ['is_active', true]
                    ]);
                })->whereHas('loan', function ($loan) use ($request) {
                    $loan->where([
                        ['fk_site', $request->fk_site],
                        ['fk_office', $request->fk_office],
                        ['is_active', true]
                    ]);
                })->where('is_active', true)
                ->orderBy('id', 'DESC')
                ->get();

            if (!$isSystemAdministrator) {
                $this->makeFieldHidden($commissions, ['visible', 'user_creator', 'user_updater']);
            }

            return $this->responseJson(null, $commissions, 201);
        } catch (Exception $ex) {
            $this->generateLog($this->CHANNEL, $ex);
            return $this->responseJson($this->MESSAGES['INDEX'], null, 501);
        }
    }

    public function store(CommissionRequest $request)
    {
        try {
            $loan = Loan::where([
                ['id', $request->fk_loan],
                ['is_active', true]
            ])->first();

            if (!$loan) {
                return $this->responseJson($this->MESSAGES['LOAN'], null, 501);
            }

            DB::beginTransaction();

            $collaborators = [];

            if ($loan->executive && isset($request->executive)) {
                $collaborators['executive'] = [
                    'id' => $loan->executive->id,
                    'commission' => $request->executive['commission'],
                    'amount' => $request->executive['amount']
                ];
            }

            if ($loan->promoter && isset($request->promoter)) {
                $collaborators['promoter'] = [
                    'id' => $loan->promoter->id,
                    'commission' => $request->promoter['commission'],
                    'amount' => $request->promoter['amount']
                ];
            }

            if ($loan->supervisor && isset($request->supervisor)) {
                $collaborators['supervisor'] = [
                    'id' => $loan->supervisor->id,
                    'commission' => $request->supervisor['commission'],
                    'amount' => $request->supervisor['amount']
                ];
            }

            foreach ($collaborators as $item => $collaborator) {
                if ($collaborator['amount'] <= 0 || $collaborator['commission'] <= 0) {
                    continue;
                }

                if (Commission::where([
                    ['fk_collaborator', $collaborator['id']],
                    ['fk_loan', $loan->id],
                    ['is_active', true]
                ])->exists()) {
                    continue;
                }

                Commission::create([
                    'fk_collaborator' => $collaborator['id'],
                    'fk_loan' => $loan->id,
                    'commissionpercent' => $collaborator['commission'],
                    'commission' => $collaborator['amount'],
                    'fk_usercreator' => $this->user()->id,
                ]);
            }

            DB::commit();
            return $this->responseJson(null, true, 201);
        } catch (Exception $ex) {
            DB::rollBack();
            $this->generateLog($this->CHANNEL, $ex);
            return $this->responseJson($this->MESSAGES['STORE'], null, 501);
        }
    }

    public function update(CommissionRequest $request)
    {
        try {
            $route = $request->route()->getName();
            $commission = Commission::findOrFail($request->id);

            $actions = [
                'commission.update' => fn() => $this->updateCommission($request, $commission),
                'commission.changeStatus' => fn() => $this->updateBooleanStatus($request, $commission),
                'commission.changeVisibility' => fn() => $this->updateBooleanStatus($request, $commission, 'visible'),
            ];

            if (array_key_exists($route, $actions)) {
                $actions[$route]();
            }

            return $this->responseJson(null, true, 201);
        } catch (Exception $ex) {
            $responses = [
                'commission.update' => $this->MESSAGES['UPDATE'],
                'commission.changeStatus' => $this->MESSAGES['STATUS'],
                'commission.changeVisibility' => $this->MESSAGES['VISIBLE']
            ];

            $this->generateLog($this->CHANNEL, $ex);
            return $this->responseJson($responses[$route], null, 501);
        }
    }

    private function updateCommission(CommissionRequest $request, Commission $commission)
    {
        if (Commission::whereNot('id', $commission->id)->where([
            ['fk_collaborator', $request->fk_collaborator],
            ['fk_loan', $request->fk_loan],
            ['is_active', true]
        ])->exists()) {
            throw new Exception($this->MEESAGES['DUPLICATED']);
        }

        $loan = Loan::where([
            ['id', $request->fk_loan],
            ['is_active', true]
        ])->first();

        if (!$loan) {
            throw new Exception($this->MESSAGES['LOAN']);
        }

        $collaborator = Collaborator::where([
            ['id', $request->fk_collaborator],
            ['is_active', true]
        ])->first();

        if (!$collaborator) {
            throw new Exception($this->MESSAGES['COLLABORATOR']);
        }

        $commissionpercent = $request->commissionpercent ?? $collaborator->commissionpercent;
        $commission = $request->commission ?? (($commissionpercent / 100) * $loan->loanamount);

        $commission->update([
            'fk_collaborator' => $collaborator->id,
            'fk_loan' => $loan->id,
            'commissionpercent' => $commissionpercent,
            'commission' => $commission,
            'fk_userupdater' => $this->user()->id,
        ]);
    }

    public function destroy(CommissionRequest $request)
    {
        try {
            $commission = Commission::findOrFail($request->id);

            $commission->update([
                'is_active' => $this->hasSpecial($request->fk_office),
                'fk_userupdater' => $this->user()->id,
            ]);

            return $this->responseJson(null, true, 201);
        } catch (Exception $ex) {
            $this->generateLog($this->CHANNEL, $ex);
            return $this->responseJson($this->MESSAGES['DESTROY'], null, 501);
        }
    }

    public function show(CommissionRequest $request)
    {
        try {
            $commission = Commission::findOrFail($request->id);

            // ID Comission
            // Collaborator
            // FK loan
            // Client
            // Loan amount
            // Loan date
            // Commission percentaje
            // Commission amount
            // Commission date

        } catch (Exception $ex) {
            $this->generateLog($this->CHANNEL, $ex);
            return $this->responseJson($this->MESSAGES['SHOW'], null, 501);
        }
    }

    public function payCommisison(CommissionRequest $request)
    {
        try {
            $commission = Commission::findOrFail($request->id);
            $commission->update([
                'payed' => $request->payed,
                'paydate' => $request->payed ? ($request->paydate ?? Carbon::now()->format('Y-m-d')) : null,
                'fk_userupdater' => $this->user()->id
            ]);

            return $this->responseJson(null, true, 201);
        } catch (Exception $ex) {
            $this->generateLog($this->CHANNEL, $ex);
            return $this->responseJson($this->MESSAGES['PAY'], null, 501);
        }
    }

    public function loanList(CommissionRequest $request)
    {
        try {
            $isSysAdmin = $this->hasSystemAdministrator();

            $loans = Loan::select('id', 'fk_client', 'fk_supervisor', 'fk_promoter', 'fk_executive', 'loanamount', 'weeklypayment', 'loandate')
                ->with(['client', 'supervisor', 'promoter', 'executive'])
                ->whereDoesntHave('commissions')->where([
                    ['fk_site', $request->fk_site],
                    ['fk_office', $request->fk_office],
                    ['is_active', true]
                ])->when(!$isSysAdmin, function ($query) {
                    $query->where('visible', true);
                })->whereNull('fk_collaborator')->get();

            $loans = $loans->map(function ($loan) {
                return [
                    'id' => $loan->id,
                    'loanamount' => $loan->loanamount,
                    'loandate' => $loan->loandate,
                    'client' => $loan->client->fullname,
                    'supervisor' => [
                        'fullname' => $loan->supervisor->fullname,
                        'commissionpercent' => Collaborator::find($loan->fk_supervisor)->commissionpercent ?? null,
                    ],
                    'promoter' => [
                        'fullname' => $loan->promoter->fullname,
                        'commissionpercent' => Collaborator::find($loan->fk_promoter)->commissionpercent ?? null,
                    ],
                    'executive' => [
                        'fullname' => $loan->executive->fullname,
                        'commissionpercent' => Collaborator::find($loan->fk_executive)->commissionpercent ?? null,
                    ],
                    'label' => "[{$loan->id}] - {$loan->client->fullname} - (\$"  . number_format(floatval($loan->loanamount), 2) . ")"
                ];
            });

            return $this->responseJson(null, $loans, 201);
        } catch (Exception $ex) {
            $this->generateLog($this->CHANNEL, $ex);
            return $this->responseJson($this->MESSAGES['LOAN-LIST'], null, 501);
        }
    }
}
