<?php

namespace App\Http\Controllers\api;

use Exception;
use App\Http\Controllers\Controller;
use App\Http\Requests\LoanTypeRequest;
use App\Models\Application\LoanType;

class LoanTypeController extends Controller
{
    private $MESSAGES = [
        'INDEX' => 'WARNING.LOANTYPE_INDEX',
        'STORE' => 'WARNING.LOANTYPE_STORE',
        'UPDATE' => 'WARNING.LOANTYPE_UPDATE',
        'DESTROY' => 'WARNING.LOANTYPE_DESTROY',
        'DUPLICATED' => 'WARNING.LOANTYPE_DUPLICATED',
        'STATUS' => 'WARNING.LOANTYPE_STATUS',
        'SPECIALITY' => 'WARNING.LOANTYPE_SPECIALITY',
        'VISIBLE' => 'WARNING.LOANTYPE_VISIBLE',
        'LIST' => 'WARNING.LOANTYPE_LIST',
        'SHOW' => 'WARNING.LOANTYPE_SHOW',
    ];

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

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

            $loantypes = LoanType::with(['user_creator', 'user_updater'])
                ->where([
                    ['fk_site', $request->fk_site],
                    ['fk_office', $request->fk_office],
                    ['is_active', !$this->hasSpecial($request->fk_office)]
                ])->when(!$isSystemAdministrator, function ($query) {
                    $query->where([
                        ['visible', true]
                    ]);
                })->orderBy('id')->get();

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

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

    public function store(LoanTypeRequest $request)
    {
        try {
            $isDuplicated = LoanType::where([
                ['loantypename', $request->loantypename],
                ['fk_site', $request->fk_site],
                ['fk_office', $request->fk_office],
                ['is_active', true]
            ])->exists();

            if ($isDuplicated) {
                return $this->responseJson($this->MESSAGES['DUPLICATED'], null, 501);
            }

            LoanType::create([
                'fk_site' => $request->fk_site,
                'fk_office' => $request->fk_office,
                'loantypename' => mb_strtoupper(trim($request->loantypename), $this->UTF_ENCODING),
                'period' => $request->period,
                'duration' => $request->duration == 0 ? null : $request->duration,
                'weeklypayment' => $request->weeklypayment == 0 ? null : $request->weeklypayment,
                'interesrate' => $request->interesrate == 0 ? null : $request->interesrate,
                'alloweddays' => mb_strtoupper(trim($request->alloweddays), $this->UTF_ENCODING),
                'funeral_insurance' => $request->funeral_insurance ?? false,
                'fk_usercreator' => $this->user()->id,
            ]);

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

    public function update(LoanTypeRequest $request)
    {
        try {
            $route = $request->route()->getName();
            $loanType = LoanType::find($request->id);

            $actions = [
                'loantype.update' => function () use ($request, $loanType) {
                    return $this->updateLoanType($request, $loanType);
                },
                'loantype.changeStatus' => function () use ($request, $loanType) {
                    return $this->changeBooleanStatus($request, $loanType, 'available');
                },
                'loantype.changeVisibility' => function () use ($request, $loanType) {
                    return $this->changeBooleanStatus($request, $loanType, 'visible'); {
                    }
                },
                'loantype.changeSpeciality' => function () use ($request, $loanType) {
                    return $this->changeBooleanStatus($request, $loanType, 'hasspecial'); {
                    }
                },
                'loantype.changeInsurance' => function () use ($request, $loanType) {
                    return $this->changeBooleanStatus($request, $loanType, 'funeral_insurance'); {
                    }
                }
            ];

            if (isset($actions[$route])) {
                $actions[$route]();
            }

            return $this->responseJson(null, true, 201);
        } catch (Exception $ex) {
            $errorResponses = [
                'loantype.update' => $this->MESSAGES['UPDATE'],
                'loantype.changeStatus' => $this->MESSAGES['STATUS'],
                'loantype.changeVisibility' => $this->MESSAGES['VISIBILITY'],
                'loantype.changeSpeciality' => $this->MESSAGES['SPECIALITY'],
                'loantype.changeInsurance' => $this->MESSAGES['INSURANCE'],
            ];

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

    public function updateLoanType(LoanTypeRequest $request, LoanType $loantype)
    {
        if (LoanType::where([
            ['id', '<>', $request->id],
            ['fk_site', $request->fk_site],
            ['fk_office', $request->fk_office],
            ['is_active', true]
        ])->where(function ($query) use ($request) {
            $query->where('loantypename', mb_strtoupper(trim($request->loantypename), $this->UTF_ENCODING))
                ->orWhere([
                    ['duration', $request->duration],
                    ['period', $request->period],
                    ['alloweddays', $request->alloweddays]
                ]);
        })->exists()) {
            throw new Exception($this->MESSAGES['DUPLICATED'], 501);
        }

        $loantype->update([
            'loantypename' => mb_strtoupper(trim($request->loantypename), $this->UTF_ENCODING),
            'period' => $request->period,
            'duration' => $request->duration == 0 ? null : $request->duration,
            'weeklypayment' => $request->weeklypayment == 0 ? null : $request->weeklypayment,
            'interesrate' => $request->interesrate == 0 ? null : $request->interesrate,
            'alloweddays' => mb_strtoupper(trim($request->alloweddays), $this->UTF_ENCODING),
            'fk_userupdater' => $this->user()->id,
        ]);
    }

    public function changeBooleanStatus(LoanTypeRequest $request, LoanType $loanType, $field = 'available')
    {
        $loanType->update([
            $field => $request->$field,
            'fk_userupdater' => $this->user()->id,
        ]);
    }

    public function destroy(LoanTypeRequest $request)
    {
        try {
            $loanType = LoanType::findOrFail($request->id);

            $loanType->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 list(LoanTypeRequest $request)
    {
        try {
            $isSystemAdministrator = $this->hasSystemAdministrator($request->fk_office);

            $loanTypes = LoanType::select(
                'id',
                'loantypename',
                'period',
                'duration',
                'weeklypayment',
                'interesrate',
                'alloweddays'
            )->where([
                ['fk_site', $request->fk_site],
                ['fk_office', $request->fk_office],
                ['available', true],
                ['is_active', true]
            ])->when(!$isSystemAdministrator, fn($query) => $query->where('visible', true))
                ->orderBy('loantypename')->get();

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