<?php

namespace App\Http\Controllers\Modules\Employee;

use App\Http\Controllers\Controller;
use App\Http\Traits\HasRoleViews;
use App\Models\EmployeeDetails;
use App\Models\EmployeeLeave;
use App\Models\EmployeeLeaveBalance;
use App\Services\Employee\LeaveService;
use Illuminate\Http\Request;
use Illuminate\Http\JsonResponse;
use Illuminate\Support\Facades\Log;
use PhpOffice\PhpSpreadsheet\IOFactory;

/**
 * Unified Leave Management Controller
 *
 * Handles employee leave applications, approvals, and balance tracking.
 */
class LeaveController extends Controller
{
    use HasRoleViews;

    protected LeaveService $leaveService;

    public function __construct(LeaveService $leaveService)
    {
        $this->leaveService = $leaveService;
    }

    /**
     * Display leave management page
     */
    public function index(Request $request)
    {
        $status = $request->input('status');
        $employeeId = $request->input('employee_id');

        $leaves = $this->leaveService->getAll();

        if ($status) {
            $leaves = $leaves->where('status', $status);
        }
        if ($employeeId) {
            $leaves = $leaves->where('employee_id', $employeeId);
        }

        $employees = EmployeeDetails::where('status', EmployeeDetails::STATUS_ACTIVE)->get();
        $pendingCount = $this->leaveService->getPending()->count();
        $leaveTypes = [
            EmployeeLeave::TYPE_CL,
            EmployeeLeave::TYPE_SL,
            EmployeeLeave::TYPE_PL,
            EmployeeLeave::TYPE_LOP,
            EmployeeLeave::TYPE_COMP_OFF,
            EmployeeLeave::TYPE_MATERNITY,
            EmployeeLeave::TYPE_PATERNITY,
        ];

        return $this->roleView('employee.leave', compact(
            'leaves',
            'employees',
            'pendingCount',
            'leaveTypes',
            'status',
            'employeeId'
        ));
    }

    /**
     * Get leave data for DataTable
     */
    public function list(Request $request): JsonResponse
    {
        $status = $request->input('status');

        if ($status) {
            $leaves = $this->leaveService->getByStatus($status);
        } else {
            $leaves = $this->leaveService->getAll();
        }

        return response()->json(['data' => $leaves]);
    }

    /**
     * Store a new leave application
     */
    public function store(Request $request)
    {
        $validated = $request->validate([
            'employee_id' => 'required|exists:employees,id',
            'leave_type' => 'required|string|in:' . implode(',', [
                EmployeeLeave::TYPE_CL,
                EmployeeLeave::TYPE_SL,
                EmployeeLeave::TYPE_PL,
                EmployeeLeave::TYPE_LOP,
                EmployeeLeave::TYPE_COMP_OFF,
                EmployeeLeave::TYPE_MATERNITY,
                EmployeeLeave::TYPE_PATERNITY,
            ]),
            'leave_from' => 'required|date',
            'leave_to' => 'required|date|after_or_equal:leave_from',
            'duration_type' => 'nullable|string|in:Full Day,Half Day',
            'half_type' => 'nullable|string|in:First Half,Second Half',
            'reason' => 'required|string|max:1000',
        ]);

        try {
            $leave = $this->leaveService->applyLeave($validated);

            if ($request->ajax()) {
                return response()->json([
                    'success' => true,
                    'message' => 'Leave application submitted successfully',
                    'data' => $leave,
                ]);
            }

            return redirect()->back()->with('success', 'Leave application submitted successfully.');
        } catch (\Exception $e) {
            Log::error('Failed to apply leave: ' . $e->getMessage());

            if ($request->ajax()) {
                return response()->json([
                    'success' => false,
                    'message' => $e->getMessage(),
                ], 400);
            }

            return redirect()->back()->with('error', $e->getMessage());
        }
    }

    /**
     * Get leave for editing
     */
    public function edit(int $id): JsonResponse
    {
        try {
            $leave = $this->leaveService->findByIdOrFail($id);
            return response()->json([
                'success' => true,
                'data' => $leave,
            ]);
        } catch (\Exception $e) {
            return response()->json([
                'success' => false,
                'message' => 'Leave application not found',
            ], 404);
        }
    }

    /**
     * Update leave application
     */
    public function update(Request $request, int $id): JsonResponse
    {
        $validated = $request->validate([
            'leave_type' => 'required|string',
            'leave_from' => 'required|date',
            'leave_to' => 'required|date|after_or_equal:leave_from',
            'duration_type' => 'nullable|string|in:Full Day,Half Day',
            'half_type' => 'nullable|string|in:First Half,Second Half',
            'reason' => 'required|string|max:1000',
        ]);

        try {
            $leave = $this->leaveService->update($id, $validated);

            return response()->json([
                'success' => true,
                'message' => 'Leave application updated successfully',
                'data' => $leave,
            ]);
        } catch (\Exception $e) {
            Log::error('Failed to update leave: ' . $e->getMessage());
            return response()->json([
                'success' => false,
                'message' => 'Failed to update leave application',
            ], 500);
        }
    }

    /**
     * Approve leave application (SuperAdmin/Manager only)
     */
    public function approve(Request $request, int $id): JsonResponse
    {
        if (!$this->isSuperAdmin() && !$this->isManager()) {
            return response()->json([
                'success' => false,
                'message' => 'Unauthorized to approve leave',
            ], 403);
        }

        $remarks = $request->input('remarks');

        try {
            $leave = $this->leaveService->approveLeave($id, $remarks);

            return response()->json([
                'success' => true,
                'message' => 'Leave approved successfully',
                'data' => $leave,
            ]);
        } catch (\Exception $e) {
            Log::error('Failed to approve leave: ' . $e->getMessage());
            return response()->json([
                'success' => false,
                'message' => $e->getMessage(),
            ], 400);
        }
    }

    /**
     * Reject leave application (SuperAdmin/Manager only)
     */
    public function reject(Request $request, int $id): JsonResponse
    {
        if (!$this->isSuperAdmin() && !$this->isManager()) {
            return response()->json([
                'success' => false,
                'message' => 'Unauthorized to reject leave',
            ], 403);
        }

        $validated = $request->validate([
            'remarks' => 'required|string|max:500',
        ]);

        try {
            $leave = $this->leaveService->rejectLeave($id, $validated['remarks']);

            return response()->json([
                'success' => true,
                'message' => 'Leave rejected',
                'data' => $leave,
            ]);
        } catch (\Exception $e) {
            Log::error('Failed to reject leave: ' . $e->getMessage());
            return response()->json([
                'success' => false,
                'message' => $e->getMessage(),
            ], 400);
        }
    }

    /**
     * Cancel leave application
     */
    public function cancel(int $id): JsonResponse
    {
        try {
            $leave = $this->leaveService->cancelLeave($id);

            return response()->json([
                'success' => true,
                'message' => 'Leave cancelled successfully',
                'data' => $leave,
            ]);
        } catch (\Exception $e) {
            Log::error('Failed to cancel leave: ' . $e->getMessage());
            return response()->json([
                'success' => false,
                'message' => $e->getMessage(),
            ], 400);
        }
    }

    /**
     * Delete leave application
     */
    public function destroy(int $id): JsonResponse
    {
        if (!$this->isSuperAdmin() && !$this->isManager()) {
            return response()->json(['success' => false, 'message' => 'Unauthorized.'], 403);
        }

        try {
            $this->leaveService->delete($id);

            return response()->json([
                'success' => true,
                'message' => 'Leave application deleted',
            ]);
        } catch (\Exception $e) {
            Log::error('Failed to delete leave: ' . $e->getMessage());
            return response()->json([
                'success' => false,
                'message' => 'Failed to delete leave application',
            ], 500);
        }
    }

    /**
     * Get leave balance for an employee
     */
    public function getBalance(int $employeeId): JsonResponse
    {
        $balance = $this->leaveService->getLeaveBalance($employeeId);

        return response()->json([
            'success' => true,
            'data' => $balance,
        ]);
    }

    /**
     * Display leave balance page
     */
    public function balanceIndex()
    {
        $employees = EmployeeDetails::where('status', EmployeeDetails::STATUS_ACTIVE)->get();
        $year = request('year', now()->year);
        $balances = EmployeeLeaveBalance::with('employee')
            ->where('year', $year)
            ->get();

        return $this->roleView('employee.leave_balance', compact('employees', 'balances', 'year'));
    }

    /**
     * Update leave balance
     */
    public function updateBalance(Request $request): JsonResponse
    {
        if (!$this->isSuperAdmin()) {
            return response()->json([
                'success' => false,
                'message' => 'Unauthorized',
            ], 403);
        }

        $validated = $request->validate([
            'employee_id' => 'required|exists:employees,id',
            'year' => 'required|integer|min:2020|max:2100',
            'cl_balance' => 'nullable|numeric|min:0',
            'sl_balance' => 'nullable|numeric|min:0',
            'pl_balance' => 'nullable|numeric|min:0',
        ]);

        try {
            $balance = EmployeeLeaveBalance::updateOrCreate(
                [
                    'employee_id' => $validated['employee_id'],
                    'year' => $validated['year'],
                ],
                [
                    'cl_balance' => $validated['cl_balance'] ?? 0,
                    'sl_balance' => $validated['sl_balance'] ?? 0,
                    'pl_balance' => $validated['pl_balance'] ?? 0,
                ]
            );

            return response()->json([
                'success' => true,
                'message' => 'Leave balance updated successfully',
                'data' => $balance,
            ]);
        } catch (\Exception $e) {
            Log::error('Failed to update leave balance: ' . $e->getMessage());
            return response()->json([
                'success' => false,
                'message' => 'Failed to update leave balance',
            ], 500);
        }
    }

    /**
     * Get pending leaves for approval dashboard
     */
    public function pending(): JsonResponse
    {
        $leaves = $this->leaveService->getPending();

        return response()->json([
            'success' => true,
            'data' => $leaves,
            'count' => $leaves->count(),
        ]);
    }

    /**
     * Import leave applications from Excel
     */
    public function import(Request $request)
    {
        $request->validate([
            'import_file' => 'required|file|mimes:xlsx,xls',
        ]);

        $file = $request->file('import_file');

        try {
            $spreadsheet = IOFactory::load($file->getPathname());
            $sheet = $spreadsheet->getActiveSheet();
            $rows = $sheet->toArray();

            $imported = 0;
            $errors = [];

            foreach ($rows as $index => $row) {
                if ($index === 0) continue; // Skip header
                if (empty($row[0])) continue;

                $employeeCode = trim($row[0]);
                $employee = EmployeeDetails::where('employee_id', $employeeCode)->first();

                if (!$employee) {
                    $errors[] = "Row " . ($index + 1) . ": Employee '$employeeCode' not found";
                    continue;
                }

                try {
                    $this->leaveService->applyLeave([
                        'employee_id' => $employee->id,
                        'leave_type' => $row[1] ?? EmployeeLeave::TYPE_CL,
                        'leave_from' => $row[2],
                        'leave_to' => $row[3],
                        'reason' => $row[4] ?? 'Imported leave',
                    ]);
                    $imported++;
                } catch (\Exception $e) {
                    $errors[] = "Row " . ($index + 1) . ": " . $e->getMessage();
                }
            }

            $message = "Imported $imported leave applications.";
            if (!empty($errors)) {
                Log::warning('Leave import errors:', $errors);
                $message .= " " . count($errors) . " rows failed.";
            }

            return back()->with('success', $message);
        } catch (\Exception $e) {
            Log::error('Leave import error: ' . $e->getMessage());
            return back()->with('error', 'Failed to import file.');
        }
    }
}
