<?php

namespace App\Http\Controllers\Admin;

use App\Http\Controllers\Controller;
use App\AgreementType;
use App\ConsumerApplication;
use App\LoanAgreementLog;
use App\LoanHypothecationModel;
use App\LoanHypothecation\DigioHypothecation;
use App\ConsumerApplicationFiles;
use Carbon\Carbon;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Log;
use Illuminate\Support\Facades\Mail;
use Illuminate\Support\Facades\Validator;

class LoanAgreementController extends Controller
{
    /**
     * Display Checker listing of loan agreement deletion requests
     */
    public function index(Request $request)
    {
        $query = LoanAgreementLog::with([
            'application' => function ($q) {
                $q->select('id', 'name', 'merchant_id', 'state', 'approved_amount');
            },
            'application.merchant' => function ($q) {
                $q->select('id', 'merchant_name');
            },
            'agreementType',
            'maker',
            'checker'
        ]);

        // Search by Application ID
        if ($request->filled('application_id')) {
            $query->where('application_id', trim($request->get('application_id')));
        }

        // Filter by Status
        if ($request->filled('status') && $request->get('status') !== 'ALL') {
            $query->where('status', $request->get('status'));
        }

        $requests = $query->orderBy('created_at', 'desc')->paginate(20);

        return view('admin.loan_agreement.index', [
            'requests'       => $requests,
            'searchAppId'    => $request->get('application_id', ''),
            'selectedStatus' => $request->get('status', 'ALL')
        ]);
    }

    /**
     * Check if an application is eligible for loan agreement deletion request
     * and fetch active reason types and status flags.
     */
    public function checkEligibility(Request $request)
    {
        if (!LoanAgreementLog::hasMakerPermission()) {
            return $this->forbidden();
        }

        $appId = $request->get('id') ?: $request->get('application_id');
        if (!$appId) {
            return response()->json([
                'status'  => 'FAIL',
                'message' => 'Application ID is required.'
            ], 400);
        }

        $application = ConsumerApplication::find($appId, ['id', 'state']);
        if (!$application) {
            return response()->json([
                'status'  => 'FAIL',
                'message' => 'Application not found.'
            ], 404);
        }

        $hasHypothecation = LoanHypothecationModel::where('application_id', $appId)
            ->whereNull('deleted_at')
            ->exists();

        $canRaise = LoanAgreementLog::canRaiseRequest($appId);

        return response()->json([
            'status'            => 'OK',
            'application_id'    => (int) $appId,
            'has_hypothecation' => $hasHypothecation,
            'can_raise'         => $canRaise['can_raise'],
            'message'           => $canRaise['message'],
            'reason_types'      => AgreementType::active()->get(['id', 'name']),
            'app_state'         => strtolower(trim((string) $application->state)),
        ], 200);
    }

    /**
     * Maker action: Submit a new loan agreement deletion request
     */
    public function storeRequest(Request $request)
    {
        if (!LoanAgreementLog::hasMakerPermission()) {
            return $this->forbidden();
        }

        $validator = Validator::make($request->all(), [
            'application_id'    => 'required|integer',
            'agreement_type_id' => 'required|integer|exists:agreement_types,id,is_active,1,deleted_at,NULL',
            'maker_reason'      => 'required|string|min:3'
        ], [
            'maker_reason.required'    => 'Maker reason / comments is required.',
            'agreement_type_id.exists' => 'Selected reason type is invalid or inactive.'
        ]);

        if ($validator->fails()) {
            return response()->json([
                'status'  => 'FAIL',
                'message' => $validator->errors()->first()
            ], 422);
        }

        $appId = $request->get('application_id');

        // Lock the application row so concurrent submissions cannot both pass the pending check
        $result = DB::transaction(function () use ($request, $appId) {
            ConsumerApplication::where('id', $appId)->lockForUpdate()->first(['id']);

            $canRaise = LoanAgreementLog::canRaiseRequest($appId);
            if (!$canRaise['can_raise']) {
                return $canRaise;
            }

            $canRaise['log'] = LoanAgreementLog::create([
                'application_id'    => $appId,
                'agreement_type_id' => $request->get('agreement_type_id'),
                'maker_id'          => Auth::check() ? Auth::id() : 107,
                'maker_reason'      => trim($request->get('maker_reason')),
                'status'            => LoanAgreementLog::STATUS_PENDING
            ]);

            return $canRaise;
        });

        if (!$result['can_raise']) {
            return response()->json([
                'status'  => 'FAIL',
                'message' => $result['message']
            ], 400);
        }

        // Send Email notification for new deletion request
        $this->sendCreationEmail($result['log']);

        return response()->json([
            'status'  => 'OK',
            'message' => 'Loan agreement deletion request submitted successfully.'
        ], 200);
    }

    /**
     * Checker action: Approve or Reject a deletion request
     */
    public function updateStatus(Request $request)
    {
        if (!LoanAgreementLog::hasCheckerPermission()) {
            return $this->forbidden();
        }

        $validator = Validator::make($request->all(), [
            'id'               => 'required|integer',
            'status'           => 'required|in:APPROVED,REJECTED',
            'checker_comments' => 'nullable|string'
        ]);

        if ($validator->fails()) {
            return response()->json([
                'status'  => 'FAIL',
                'message' => $validator->errors()->first()
            ], 422);
        }

        $newStatus = $request->get('status');
        $checkerId = Auth::check() ? Auth::id() : 107;
        $comments  = $request->filled('checker_comments') ? trim($request->get('checker_comments')) : null;
        $now       = Carbon::now();

        // Conditional update so only one checker can action a PENDING request
        $affected = LoanAgreementLog::where('id', $request->get('id'))
            ->where('status', LoanAgreementLog::STATUS_PENDING)
            ->update([
                'status'           => $newStatus,
                'checker_user_id'  => $checkerId,
                'checker_comments' => $comments,
                'updated_at'       => $now
            ]);

        if (!$affected) {
            return response()->json([
                'status'  => 'FAIL',
                'message' => 'Request not found or it is no longer in PENDING status.'
            ], 400);
        }

        $log = LoanAgreementLog::with(['application', 'agreementType', 'maker', 'checker'])->find($request->get('id'));

        $digioResponse = null;
        // If APPROVED, trigger Digio cancellation API and always soft-delete the loan hypothecation record
        if ($newStatus === LoanAgreementLog::STATUS_APPROVED) {
            try {
                $digio = new DigioHypothecation(new Request(['id' => $log->application_id]));
                $digioResponse = $digio->cancelDocument($log->application_id);
                Log::info('Digio agreement cancellation on checker approval', [
                    'application_id' => $log->application_id,
                    'result'         => $digioResponse
                ]);
            } catch (\Exception $e) {
                Log::error('Digio agreement cancellation error on checker approval: ' . $e->getMessage(), [
                    'application_id' => $log->application_id,
                    'trace'          => $e->getTraceAsString()
                ]);
            }

            // Always soft-delete active loan hypothecation record regardless of Digio API outcome
            LoanHypothecationModel::where('application_id', $log->application_id)
                ->whereNull('deleted_at')
                ->update([
                    'deleted_at' => $now,
                    'deleted_by' => $checkerId
                ]);

            // Soft-delete hypothecation agreement files if present
            ConsumerApplicationFiles::where('consumer_application_id', $log->application_id)
                ->where('file_type', 'hypothecation_agreement')
                ->whereNull('deleted_at')
                ->update([
                    'deleted_at' => $now,
                    'deleted_by' => $checkerId
                ]);
        }

        // Send Email notification for checker decision
        $this->sendStatusUpdateEmail($log, $newStatus);

        $msg = 'Loan agreement deletion request has been ' . strtolower($newStatus) . ' successfully.';
        if ($newStatus === LoanAgreementLog::STATUS_APPROVED && isset($digioResponse['message'])) {
            $msg .= ' (' . $digioResponse['message'] . ')';
        }

        return response()->json([
            'status'         => 'OK',
            'message'        => $msg,
            'digio_response' => $digioResponse
        ], 200);
    }

    /**
     * Fetch complete audit log history for an application
     */
    public function getLogs($application_id)
    {
        if (!LoanAgreementLog::hasCheckerPermission()) {
            return $this->forbidden();
        }

        $logs = LoanAgreementLog::with(['agreementType', 'maker', 'checker'])
            ->where('application_id', $application_id)
            ->orderBy('created_at', 'desc')
            ->get();

        return response()->json([
            'status' => 'OK',
            'data'   => $logs
        ], 200);
    }

    /**
     * Fetch all reason agreement types for management list
     */
    public function getAgreementTypes(Request $request)
    {
        if (!LoanAgreementLog::hasCheckerPermission()) {
            return $this->forbidden();
        }

        $types = AgreementType::with(['creator' => function ($q) {
            $q->select('id', 'name');
        }])
        ->orderBy('id', 'asc')
        ->get();

        $formatted = $types->map(function ($type) {
            return [
                'id'         => $type->id,
                'name'       => $type->name,
                'is_active'  => (int)$type->is_active,
                'user_id'    => $type->created_by,
                'user_name'  => $type->creator ? $type->creator->name : ($type->created_by ? 'User #' . $type->created_by : 'Default'),
                'created_at' => $type->created_at ? $type->created_at->format('d M Y, h:i A') : '-',
                'updated_at' => $type->updated_at ? $type->updated_at->format('d M Y, h:i A') : '-',
            ];
        });

        return response()->json([
            'status' => 'OK',
            'data'   => $formatted
        ], 200);
    }

    /**
     * Store new agreement reason type
     */
    public function storeAgreementType(Request $request)
    {
        if (!LoanAgreementLog::hasCheckerPermission()) {
            return $this->forbidden();
        }

        $validator = Validator::make($request->all(), [
            'name' => 'required|string|max:255|unique:agreement_types,name,NULL,id,deleted_at,NULL'
        ], [
            'name.required' => 'Reason type name is required.',
            'name.unique'   => 'This agreement reason type already exists.'
        ]);

        if ($validator->fails()) {
            return response()->json([
                'status'  => 'FAIL',
                'message' => $validator->errors()->first()
            ], 422);
        }

        $userId = Auth::check() ? Auth::id() : 107;

        $type = AgreementType::create([
            'name'       => trim($request->get('name')),
            'is_active'  => 1,
            'created_by' => $userId
        ]);

        return response()->json([
            'status'  => 'OK',
            'message' => 'Agreement reason type created successfully.',
            'data'    => $type
        ], 200);
    }

    /**
     * Common method to update an existing agreement reason type (edit name and/or toggle active status)
     */
    public function updateAgreementType(Request $request)
    {
        if (!LoanAgreementLog::hasCheckerPermission()) {
            return $this->forbidden();
        }

        $typeId = $request->get('id');

        $rules = [
            'id' => 'required|integer|exists:agreement_types,id'
        ];

        if ($request->has('name')) {
            $rules['name'] = 'required|string|max:255|unique:agreement_types,name,' . $typeId . ',id,deleted_at,NULL';
            $rules['is_active'] = 'nullable|in:0,1';
        }

        $validator = Validator::make($request->all(), $rules, [
            'name.required' => 'Reason type name is required.',
            'name.unique'   => 'Another agreement reason type with this name already exists.'
        ]);

        if ($validator->fails()) {
            return response()->json([
                'status'  => 'FAIL',
                'message' => $validator->errors()->first()
            ], 422);
        }

        $type = AgreementType::findOrFail($typeId);
        $userId = Auth::check() ? Auth::id() : 107;
        $message = 'Agreement reason type updated successfully.';

        if ($request->has('name')) {
            $type->name = trim($request->get('name'));
            if ($request->has('is_active')) {
                $type->is_active = (int)$request->get('is_active');
            }
        } elseif ($request->has('toggle') || $request->has('is_active')) {
            if ($request->has('is_active')) {
                $type->is_active = (int)$request->get('is_active');
            } else {
                $type->is_active = $type->is_active == 1 ? 0 : 1;
            }
            $message = 'Reason type status changed to ' . ($type->is_active ? 'Active' : 'Inactive') . '.';
        } else {
            // Default toggle behavior when only id is provided
            $type->is_active = $type->is_active == 1 ? 0 : 1;
            $message = 'Reason type status changed to ' . ($type->is_active ? 'Active' : 'Inactive') . '.';
        }

        $type->created_by = $userId; // Record user id who edited/updated
        $type->updated_at = Carbon::now();
        $type->save();

        return response()->json([
            'status'    => 'OK',
            'is_active' => $type->is_active,
            'message'   => $message,
            'data'      => $type
        ], 200);
    }

    /**
     * Send email notification when a deletion request is raised
     */
    protected function sendCreationEmail($log)
    {
        try {
            $log->loadMissing(['application', 'agreementType', 'maker']);

            $appId = $log->application_id;
            $recipientEmail = 'vedant.jadhav@creditfair.in';
            $fromEmail = config('mail.from.address', 'info@creditfair.in');

            Mail::send('emails.loan_agreement.request_created', [
                'appId'            => $appId,
                'customerName'     => $log->application ? $log->application->name : 'N/A',
                'reasonType'       => $log->agreementType ? $log->agreementType->name : 'N/A',
                'makerName'        => $log->maker ? $log->maker->name : ('Maker #' . $log->maker_id),
                'makerNote'        => !empty($log->maker_reason) ? $log->maker_reason : 'No additional notes provided',
                'checkerPortalUrl' => url('admin/loan-agreements'),
            ], function ($message) use ($recipientEmail, $fromEmail, $appId) {
                $message->to($recipientEmail)
                    ->from($fromEmail, 'Credit Fair')
                    ->subject("Loan Agreement Deletion Request – Approval Required (App #{$appId})");
            });
        } catch (\Exception $e) {
            Log::error('Failed to send loan agreement creation email: ' . $e->getMessage(), [
                'log_id' => $log->id ?? null,
                'trace'  => $e->getTraceAsString()
            ]);
        }
    }

    /**
     * Send email notification when checker approves or rejects a request
     */
    protected function sendStatusUpdateEmail($log, $newStatus)
    {
        try {
            $log->loadMissing(['application', 'agreementType', 'maker', 'checker']);

            $maker = $log->maker;
            if (!$maker || empty($maker->email)) {
                Log::warning("Loan agreement status update email skipped: No maker email found for request ID {$log->id}.");
                return;
            }

            $appId = $log->application_id;
            $makerEmail = $maker->email;
            $statusText = strtoupper($newStatus);
            $fromEmail = config('mail.from.address', 'info@creditfair.in');

            Mail::send('emails.loan_agreement.status_updated', [
                'appId'           => $appId,
                'statusText'      => $statusText,
                'isApproved'      => $statusText === LoanAgreementLog::STATUS_APPROVED,
                'customerName'    => $log->application ? $log->application->name : 'N/A',
                'reasonType'      => $log->agreementType ? $log->agreementType->name : 'N/A',
                'makerName'       => !empty($maker->name) ? $maker->name : 'Maker',
                'checkerName'     => ($log->checker && !empty($log->checker->name)) ? $log->checker->name : 'Checker',
                'checkerComments' => !empty($log->checker_comments) ? $log->checker_comments : 'No comments provided',
            ], function ($message) use ($makerEmail, $fromEmail, $appId, $statusText) {
                $message->to($makerEmail)
                    ->from($fromEmail, 'Credit Fair')
                    ->subject("Loan Agreement Deletion Request {$statusText} (App #{$appId})");
            });
        } catch (\Exception $e) {
            Log::error('Failed to send loan agreement status update email: ' . $e->getMessage(), [
                'log_id' => $log->id ?? null,
                'trace'  => $e->getTraceAsString()
            ]);
        }
    }

    protected function forbidden()
    {
        return response()->json([
            'status'  => 'FAIL',
            'message' => 'You do not have permission to perform this action.'
        ], 403);
    }
}
