<?php

namespace App\Modules\HR\Payroll\Http\Controllers;

use App\Http\Controllers\Controller;
use App\Modules\HR\Core\Models\Employee;
use App\Modules\HR\Payroll\Models\Loan;
use App\Modules\HR\Payroll\Models\EmployeeLoan;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\DB;
use PhpOffice\PhpSpreadsheet\IOFactory;
use Yajra\DataTables\Facades\DataTables;

class EmployeeLoanController extends Controller
{
    public function index(Request $request)
    {
        if ($request->ajax()) {
            $query = EmployeeLoan::with(['employee', 'loan'])
                ->orderBy('application_date', 'desc');

            return DataTables::of($query)
                ->addIndexColumn()
                ->addColumn('emp_no', function ($row) {
                    return $row->employee->employee_code ?? '-';
                })
                ->addColumn('emp_name', function ($row) {
                    return $row->employee->first_name . ' ' . $row->employee->last_name;
                })
                ->addColumn('loan_name', function ($row) {
                    return $row->loan->name ?? '-';
                })
                ->editColumn('status', function ($row) {
                    $badge = $row->status_badge;
                    return '<span class="badge bg-' . $badge . '">' . ucfirst($row->status) . '</span>';
                })
                ->addColumn('action', function ($row) {
                    return view('payroll::employee-loans/partials/actions', compact('row'))->render();
                })
                ->rawColumns(['status', 'action'])
                ->make(true);
        }

        $loans = Loan::where('status', true)->orderBy('name')->get();
        return view('payroll::employee-loans/index', compact('loans'));
    }

    public function create()
    {
        $employees = Employee::where('status', 'active')
            ->select('id', 'employee_code', 'first_name', 'last_name')
            ->orderBy('first_name')
            ->get()
            ->map(function ($emp) {
                return [
                    'id' => $emp->id,
                    'text' => $emp->employee_code . ' - ' . $emp->first_name . ' ' . $emp->last_name
                ];
            });

        $loans = Loan::where('status', true)
            ->orderBy('name')
            ->get();

        return view('payroll::employee-loans/create', compact('employees', 'loans'));
    }

    public function store(Request $request)
    {
        $validated = $request->validate([
            'employee_id' => 'required|exists:employees,id',
            'loan_id' => 'required|exists:loans,id',
            'application_date' => 'required|date',
            'full_amount' => 'required|numeric|min:0',
            'approved_amount' => 'nullable|numeric|min:0',
            'interest_rate' => 'required|numeric|min:0|max:100',
            'repayment_period' => 'required|integer|min:1',
            'installment_amount' => 'required|numeric|min:0',
            'remarks' => 'nullable|string',
        ]);

        $employeeLoan = new EmployeeLoan($validated);
        $employeeLoan->loan_number = $employeeLoan->generateLoanNumber();
        $employeeLoan->status = 'approved';
        $employeeLoan->remaining_amount = $validated['approved_amount'] ?? $validated['full_amount'];
        $employeeLoan->save();

        return response()->json([
            'status' => true,
            'message' => 'Loan application created successfully',
        ]);
    }

    public function edit(EmployeeLoan $employeeLoan)
    {
        $employees = Employee::where('status', 'active')
            ->select('id', 'employee_code', 'first_name', 'last_name')
            ->orderBy('first_name')
            ->get()
            ->map(function ($emp) {
                return [
                    'id' => $emp->id,
                    'text' => $emp->employee_code . ' - ' . $emp->first_name . ' ' . $emp->last_name
                ];
            });

        $loans = Loan::where('status', true)
            ->orderBy('name')
            ->get();

        return view('payroll::employee-loans/edit', compact('employeeLoan', 'employees', 'loans'));
    }

    public function update(Request $request, EmployeeLoan $employeeLoan)
    {
        $validated = $request->validate([
            'employee_id' => 'required|exists:employees,id',
            'loan_id' => 'required|exists:loans,id',
            'application_date' => 'required|date',
            'full_amount' => 'required|numeric|min:0',
            'approved_amount' => 'nullable|numeric|min:0',
            'interest_rate' => 'required|numeric|min:0|max:100',
            'repayment_period' => 'required|integer|min:1',
            'installment_amount' => 'required|numeric|min:0',
            'remarks' => 'nullable|string',
            'status' => 'nullable|in:pending,approved,rejected,active,completed',
        ]);

        $employeeLoan->update($validated);

        return response()->json([
            'status' => true,
            'message' => 'Loan application updated successfully',
        ]);
    }

    public function destroy(EmployeeLoan $employeeLoan)
    {
        if (in_array($employeeLoan->status, ['active', 'completed'])) {
            return response()->json([
                'status' => false,
                'message' => 'Cannot delete loan that is active or completed',
            ], 400);
        }

        $employeeLoan->delete();

        return response()->json([
            'status' => true,
            'message' => 'Loan application deleted successfully',
        ]);
    }

    public function approve(EmployeeLoan $employeeLoan)
    {
        if ($employeeLoan->status !== 'pending') {
            return response()->json([
                'status' => false,
                'message' => 'Only pending loans can be approved',
            ], 400);
        }

        $employeeLoan->update([
            'status' => 'approved',
            'start_date' => now(),
            'end_date' => now()->addMonths($employeeLoan->repayment_period),
        ]);

        return response()->json([
            'status' => true,
            'message' => 'Loan approved successfully',
        ]);
    }

    public function reject(EmployeeLoan $employeeLoan)
    {
        if ($employeeLoan->status !== 'pending') {
            return response()->json([
                'status' => false,
                'message' => 'Only pending loans can be rejected',
            ], 400);
        }

        $employeeLoan->update(['status' => 'rejected']);

        return response()->json([
            'status' => true,
            'message' => 'Loan rejected successfully',
        ]);
    }

    public function activate(EmployeeLoan $employeeLoan)
    {
        if ($employeeLoan->status !== 'approved') {
            return response()->json([
                'status' => false,
                'message' => 'Only approved loans can be activated',
            ], 400);
        }

        $employeeLoan->update(['status' => 'active']);

        return response()->json([
            'status' => true,
            'message' => 'Loan activated successfully',
        ]);
    }

    public function getEmployeeInfo(Employee $employee)
    {
        return response()->json([
            'employee_code' => $employee->employee_code,
            'name' => $employee->first_name . ' ' . $employee->last_name,
            'department' => $employee->department->name ?? '-',
            'designation' => $employee->designation->name ?? '-',
        ]);
    }

    public function getLoanInfo(Loan $loan)
    {
        return response()->json([
            'name' => $loan->name,
            'min_amount' => $loan->min_amount,
            'max_amount' => $loan->max_amount,
            'min_installments' => $loan->min_installments,
            'max_installments' => $loan->max_installments,
            'interest_rate' => $loan->interest_rate,
        ]);
    }

    public function downloadTemplate()
    {
        $headers = [
            'Content-Type' => 'text/csv',
            'Content-Disposition' => 'attachment; filename="loan_application_template.csv"',
        ];

        $content = "emp_no,application_date,full_amount,interest_rate,repayment_period,installment_amount,remarks\n";
        $content .= "EMP001,2026-01-01,50000.00,5.00,12,4375.00,Optional remarks\n";
        $content .= "EMP002,2026-01-01,100000.00,5.00,24,4375.00,\n";

        return response($content, 200, $headers);
    }

    public function importData(Request $request)
    {
        $request->validate([
            'loan_id' => 'required|exists:loans,id',
            'file'    => 'required|file|mimes:csv,xlsx,xls,txt',
        ]);

        $loan = Loan::findOrFail($request->loan_id);

        try {
            $spreadsheet = IOFactory::load($request->file('file')->getPathname());
            $rows = $spreadsheet->getActiveSheet()->toArray(null, true, true, false);
        } catch (\Exception $e) {
            return response()->json(['status' => false, 'message' => 'Could not read file: ' . $e->getMessage()], 422);
        }

        if (empty($rows)) {
            return response()->json(['status' => false, 'message' => 'The file is empty.'], 422);
        }

        $header = array_map(fn($v) => strtolower(trim((string) $v)), $rows[0]);

        $required = ['emp_no', 'application_date', 'full_amount', 'interest_rate', 'repayment_period', 'installment_amount'];
        foreach ($required as $col) {
            if (array_search($col, $header) === false) {
                return response()->json([
                    'status'  => false,
                    'message' => "Invalid file format. Missing required column: {$col}",
                ], 422);
            }
        }

        $colIdx = [];
        foreach (['emp_no', 'application_date', 'full_amount', 'interest_rate', 'repayment_period', 'installment_amount', 'remarks'] as $col) {
            $colIdx[$col] = array_search($col, $header);
        }

        $employees = Employee::where('status', 'active')
            ->pluck('id', 'employee_code')
            ->toArray();

        $inserted = 0;
        $skipped  = 0;
        $errors   = [];

        DB::beginTransaction();
        try {
            foreach (array_slice($rows, 1) as $lineNo => $row) {
                $rowNum = $lineNo + 2;

                $empNo            = trim((string) ($row[$colIdx['emp_no']] ?? ''));
                $applicationDate  = trim((string) ($row[$colIdx['application_date']] ?? ''));
                $fullAmount       = trim((string) ($row[$colIdx['full_amount']] ?? ''));
                $interestRate     = trim((string) ($row[$colIdx['interest_rate']] ?? ''));
                $repaymentPeriod  = trim((string) ($row[$colIdx['repayment_period']] ?? ''));
                $installmentAmount = trim((string) ($row[$colIdx['installment_amount']] ?? ''));
                $remarks          = $colIdx['remarks'] !== false ? trim((string) ($row[$colIdx['remarks']] ?? '')) : '';

                // Skip fully blank rows
                if ($empNo === '' && $applicationDate === '' && $fullAmount === '') {
                    continue;
                }

                if ($empNo === '') { $errors[] = "Row {$rowNum}: Missing emp_no."; $skipped++; continue; }
                if (!isset($employees[$empNo])) { $errors[] = "Row {$rowNum}: Employee '{$empNo}' not found."; $skipped++; continue; }
                if ($applicationDate === '' || !strtotime($applicationDate)) { $errors[] = "Row {$rowNum}: Invalid application_date."; $skipped++; continue; }
                if (!is_numeric($fullAmount) || (float) $fullAmount < 0) { $errors[] = "Row {$rowNum}: Invalid full_amount."; $skipped++; continue; }
                if (!is_numeric($interestRate) || (float) $interestRate < 0) { $errors[] = "Row {$rowNum}: Invalid interest_rate."; $skipped++; continue; }
                if (!is_numeric($repaymentPeriod) || (int) $repaymentPeriod < 1) { $errors[] = "Row {$rowNum}: Invalid repayment_period."; $skipped++; continue; }
                if (!is_numeric($installmentAmount) || (float) $installmentAmount < 0) { $errors[] = "Row {$rowNum}: Invalid installment_amount."; $skipped++; continue; }

                $employeeLoan = new EmployeeLoan([
                    'employee_id'        => $employees[$empNo],
                    'loan_id'            => $loan->id,
                    'application_date'   => date('Y-m-d', strtotime($applicationDate)),
                    'full_amount'        => (float) $fullAmount,
                    'interest_rate'      => (float) $interestRate,
                    'repayment_period'   => (int) $repaymentPeriod,
                    'installment_amount' => (float) $installmentAmount,
                    'remarks'            => $remarks ?: null,
                    'status'             => 'approved',
                    'remaining_amount'   => (float) $fullAmount,
                ]);
                $employeeLoan->loan_number = $employeeLoan->generateLoanNumber();
                $employeeLoan->save();

                $inserted++;
            }

            DB::commit();

            $message = "{$inserted} loan application(s) imported successfully.";
            if ($skipped > 0) {
                $message .= " {$skipped} row(s) skipped.";
            }

            return response()->json([
                'status'   => true,
                'message'  => $message,
                'inserted' => $inserted,
                'skipped'  => $skipped,
                'errors'   => $errors,
            ]);
        } catch (\Exception $e) {
            DB::rollBack();
            return response()->json(['status' => false, 'message' => 'Error importing data: ' . $e->getMessage()], 500);
        }
    }

    public function calculateInstallment(Request $request)
    {
        $amount = $request->input('amount', 0);
        $interestRate = $request->input('interest_rate', 0);
        $period = $request->input('period', 1);

        if ($period > 0) {
            $interest = ($amount * $interestRate) / 100;
            $totalAmount = $amount + $interest;
            $installment = round($totalAmount / $period, 2);

            return response()->json([
                'installment_amount' => $installment,
                'total_interest' => round($interest, 2),
                'total_repayment' => round($totalAmount, 2),
            ]);
        }

        return response()->json(['installment_amount' => 0]);
    }
}
