<?php

namespace App\Http\Controllers;

use App\Models\Appraisal;
use App\Models\AppraisalCompetency;
use App\Models\AppraisalGoal;
use App\Models\AppraisalOperation;
use App\Models\AppraisalPeriod;
use App\Models\KeyResultArea;
use App\Models\User;
use App\Services\AppraisalService;
use Illuminate\Http\Request;
use Inertia\Inertia;

class AppraisalController extends Controller
{
    protected AppraisalService $appraisalService;

    public function __construct(AppraisalService $appraisalService)
    {
        $this->appraisalService = $appraisalService;
    }

    public function index(Request $request)
    {
        $user = $request->user();

        $query = Appraisal::with([
            'employee:id,surname,firstname,designation,department_id',
            'employee.department:id,name',
            'supervisor:id,surname,firstname',
            'period:id,name,start_date,end_date',
        ]);

        // Role-based filtering
        if ($user->isStaff()) {
            $query->where('employee_id', $user->id);
        } elseif ($user->isSupervisor()) {
            $query->where(function ($q) use ($user) {
                $q->where('employee_id', $user->id)
                    ->orWhere('supervisor_id', $user->id);
            });
        } elseif ($user->isDepartmentHead() || $user->isDirector()) {
            $query->where(function ($q) use ($user) {
                $q->where('employee_id', $user->id)
                    ->orWhere('supervisor_id', $user->id)
                    ->orWhereHas('employee', fn($e) => $e->where('department_id', $user->department_id));
            });
        }

        $query->when($request->period, fn($q, $p) => $q->where('appraisal_period_id', $p))
            ->when($request->status, fn($q, $s) => $q->where('status', $s))
            ->when($request->search, fn($q, $s) => $q->whereHas('employee', fn($e) =>
                $e->where('surname', 'like', "%{$s}%")->orWhere('firstname', 'like', "%{$s}%")
            ));

        $appraisals = $query->orderByDesc('created_at')->paginate(20)->withQueryString();

        return Inertia::render('Appraisals/Index', [
            'appraisals' => $appraisals,
            'periods' => AppraisalPeriod::select('id', 'name')->orderByDesc('start_date')->get(),
            'filters' => $request->only('period', 'status', 'search'),
            'statuses' => Appraisal::STATUS_LABELS,
        ]);
    }

    public function create(Request $request)
    {
        $user = $request->user();
        $activePeriod = AppraisalPeriod::active()->first();

        if (!$activePeriod) {
            return redirect()->route('appraisals.index')->with('error', 'No active appraisal period found.');
        }

        // Available staff members for whom an appraisal can be created
        $staffQuery = User::where('is_active', true)->with('department:id,name', 'supervisor:id,surname,firstname,designation');

        if ($user->isStaff()) {
            // Staff can only create for themselves
            $staffQuery->where('id', $user->id);
        } elseif ($user->isSupervisor()) {
            // Supervisor can create for themselves or their direct subordinates
            $staffQuery->where(fn($q) => $q->where('id', $user->id)->orWhere('supervisor_id', $user->id));
        } elseif ($user->isDepartmentHead() || $user->isDirector()) {
            // HOD/Director can create for anyone in their department or themselves
            $staffQuery->where(fn($q) => $q->where('id', $user->id)->orWhere('department_id', $user->department_id));
        }
        // Admin can create for anyone

        $availableEmployees = $staffQuery->orderBy('surname')->get();

        // Selected target employee (defaults to query param or logged in user)
        $targetEmployeeId = (int) $request->input('employee_id', $user->id);
        $targetEmployee = $availableEmployees->firstWhere('id', $targetEmployeeId) ?? $user;

        // Check if an appraisal already exists for this specific employee
        $existing = Appraisal::where('appraisal_period_id', $activePeriod->id)
            ->where('employee_id', $targetEmployee->id)
            ->first();

        if ($existing && $user->isStaff()) {
            return redirect()->route('appraisals.show', $existing)->with('info', 'You already have an appraisal for this period.');
        }

        $kras = KeyResultArea::active()
            ->where(fn($q) => $q->whereNull('department_id')->orWhere('department_id', $targetEmployee->department_id))
            ->with('kpis')
            ->get();

        return Inertia::render('Appraisals/Create', [
            'period' => $activePeriod,
            'employee' => $targetEmployee->load('department:id,name', 'supervisor:id,surname,firstname,othername,designation,ippis_no,email,phone'),
            'availableEmployees' => $availableEmployees,
            'existingAppraisalId' => $existing?->id,
            'canSelectEmployee' => !$user->isStaff(),
            'kras' => $kras,
            'defaultCompetencies' => AppraisalService::DEFAULT_COMPETENCIES,
            'defaultOperations' => AppraisalService::DEFAULT_OPERATIONS,
            'ratingScale' => Appraisal::RATING_VALUES,
            'ratingLabels' => Appraisal::RATING_LABELS,
        ]);
    }

    public function store(Request $request)
    {
        $user = $request->user();
        $validated = $request->validate([
            'appraisal_period_id' => 'required|exists:appraisal_periods,id',
            'employee_id' => 'nullable|exists:users,id',
            'goals' => 'required|array|min:1',
            'goals.*.key_result_area_id' => 'nullable|exists:key_result_areas,id',
            'goals.*.kra_weight' => 'nullable|numeric|min:0|max:100',
            'goals.*.objective' => 'required|string',
            'goals.*.objective_weight' => 'required|numeric|min:0|max:100',
            'goals.*.kpi' => 'required|string',
            'goals.*.target_set' => 'required|string',
            'goals.*.unit_of_measurement' => 'nullable|string',
            'goals.*.graded_weight' => 'nullable|numeric',
            'goals.*.criteria_outstanding' => 'nullable|string',
            'goals.*.criteria_excellent' => 'nullable|string',
            'goals.*.criteria_very_good' => 'nullable|string',
            'goals.*.criteria_good' => 'nullable|string',
            'goals.*.criteria_fair' => 'nullable|string',
            'goals.*.criteria_poor' => 'nullable|string',
        ]);

        // Determine target employee
        $targetEmployeeId = $user->isStaff() ? $user->id : ($validated['employee_id'] ?? $user->id);
        $targetEmployee = User::findOrFail($targetEmployeeId);

        // Check if appraisal already exists
        $existing = Appraisal::where('appraisal_period_id', $validated['appraisal_period_id'])
            ->where('employee_id', $targetEmployee->id)
            ->first();

        if ($existing) {
            return redirect()->route('appraisals.show', $existing)->with('info', 'An appraisal already exists for this employee in this period.');
        }

        $supervisor = $targetEmployee->supervisor;
        $counterSigningOfficer = $targetEmployee->resolveCounterSigningOfficer();

        $appraisal = Appraisal::create([
            'appraisal_period_id' => $validated['appraisal_period_id'],
            'employee_id' => $targetEmployee->id,
            'supervisor_id' => $supervisor?->id ?? $user->id,
            'counter_signing_officer_id' => $counterSigningOfficer?->id,
            'status' => 'goal_setting',
        ]);

        foreach ($validated['goals'] as $index => $goalData) {
            $appraisal->goals()->create([
                ...array_filter($goalData, fn($v) => $v !== null),
                'sort_order' => $index,
            ]);
        }

        // Initialize Section 5 (Competencies) and Section 6 (Operations & Processes)
        $this->appraisalService->initializeDefaultCompetenciesAndOperations($appraisal);

        return redirect()->route('appraisals.show', $appraisal)->with('success', 'Performance Contract goals created successfully.');
    }

    public function show(Appraisal $appraisal)
    {
        $this->authorizeView($appraisal);

        $this->appraisalService->initializeDefaultCompetenciesAndOperations($appraisal);

        $appraisal->load([
            'employee:id,surname,firstname,othername,designation,ippis_no,email,phone,department_id',
            'employee.department:id,name',
            'supervisor:id,surname,firstname,othername,designation,ippis_no,email,phone',
            'counterSigningOfficer:id,surname,firstname,othername,designation,ippis_no,email,phone',
            'period:id,name,start_date,end_date',
            'goals.keyResultArea:id,name',
            'competencies',
            'operations',
        ]);

        return Inertia::render('Appraisals/Show', [
            'appraisal' => $appraisal,
            'ratingScale' => Appraisal::RATING_VALUES,
            'ratingLabels' => Appraisal::RATING_LABELS,
            'canEdit' => $appraisal->canBeEditedBy(request()->user()),
        ]);
    }

    public function edit(Appraisal $appraisal)
    {
        $user = request()->user();

        if (!$appraisal->canBeEditedBy($user)) {
            return redirect()->route('appraisals.show', $appraisal)->with('error', 'You cannot edit this appraisal in its current state.');
        }

        $this->appraisalService->initializeDefaultCompetenciesAndOperations($appraisal);

        $appraisal->load([
            'employee:id,surname,firstname,othername,designation,ippis_no,email,phone,department_id',
            'employee.department:id,name',
            'supervisor:id,surname,firstname,othername,designation,ippis_no,email,phone',
            'counterSigningOfficer:id,surname,firstname,othername,designation,ippis_no,email,phone',
            'period:id,name,start_date,end_date',
            'goals.keyResultArea:id,name',
            'competencies',
            'operations',
        ]);

        $kras = KeyResultArea::active()
            ->where(fn($q) => $q->whereNull('department_id')->orWhere('department_id', $appraisal->employee->department_id))
            ->with('kpis')
            ->get();

        $page = match (true) {
            $appraisal->status === 'supervisor_review' && $appraisal->supervisor_id === $user->id
                => 'Appraisals/SupervisorReview',
            $appraisal->status === 'counter_sign' && $appraisal->counter_signing_officer_id === $user->id
                => 'Appraisals/CounterSign',
            $appraisal->employee_id === $user->id && in_array($appraisal->status, ['draft', 'goal_setting', 'self_assessment'])
                => 'Appraisals/SelfAssessment',
            $user->isAdmin()
                => 'Appraisals/SelfAssessment',
            default => 'Appraisals/Show',
        };

        return Inertia::render($page, [
            'appraisal' => $appraisal,
            'kras' => $kras,
            'ratingScale' => Appraisal::RATING_VALUES,
            'ratingLabels' => Appraisal::RATING_LABELS,
        ]);
    }

    public function update(Request $request, Appraisal $appraisal)
    {
        $user = $request->user();

        if (!$appraisal->canBeEditedBy($user)) {
            return back()->with('error', 'You cannot edit this appraisal in its current state.');
        }

        $action = $request->input('action', 'save');

        // Handle Section 4: Goals updates
        if ($request->has('goals')) {
            foreach ($request->input('goals', []) as $goalData) {
                if (isset($goalData['id'])) {
                    $goal = AppraisalGoal::find($goalData['id']);
                    if ($goal && $goal->appraisal_id === $appraisal->id) {
                        $goal->update($goalData);
                    }
                } else {
                    $appraisal->goals()->create($goalData);
                }
            }
        }

        // Handle Section 5: Competencies updates
        if ($request->has('competencies')) {
            foreach ($request->input('competencies', []) as $compData) {
                if (isset($compData['id'])) {
                    $comp = AppraisalCompetency::find($compData['id']);
                    if ($comp && $comp->appraisal_id === $appraisal->id) {
                        $comp->update($compData);
                    }
                }
            }
        }

        // Handle Section 6: Operations & Processes updates
        if ($request->has('operations')) {
            foreach ($request->input('operations', []) as $opData) {
                if (isset($opData['id'])) {
                    $op = AppraisalOperation::find($opData['id']);
                    if ($op && $op->appraisal_id === $appraisal->id) {
                        $op->update($opData);
                    }
                }
            }
        }

        // Handle Comments and assessment text fields
        if ($request->has('supervisor_comment')) {
            $appraisal->supervisor_comment = $request->input('supervisor_comment');
        }
        if ($request->has('counter_signing_comment')) {
            $appraisal->counter_signing_comment = $request->input('counter_signing_comment');
        }
        if ($request->has('strengths')) {
            $appraisal->strengths = $request->input('strengths');
        }
        if ($request->has('areas_for_improvement')) {
            $appraisal->areas_for_improvement = $request->input('areas_for_improvement');
        }
        if ($request->has('training_needs')) {
            $appraisal->training_needs = $request->input('training_needs');
        }
        if ($request->has('employee_comment')) {
            $appraisal->employee_comment = $request->input('employee_comment');
        }

        // Recalculate full scores across Section 4 (70%), Section 5 (20%), Section 6 (10%)
        $this->appraisalService->calculateAppraisalScores($appraisal);

        // Handle workflow status transitions
        if ($action === 'submit') {
            if (in_array($appraisal->status, ['draft', 'goal_setting'])) {
                $appraisal->status = 'self_assessment';
            } elseif ($appraisal->status === 'self_assessment') {
                $this->appraisalService->transitionState($appraisal, 'supervisor_review', $user, $request->input('employee_comment'));
            } elseif ($appraisal->status === 'supervisor_review') {
                $nextState = $appraisal->counter_signing_officer_id ? 'counter_sign' : 'completed';
                $this->appraisalService->transitionState($appraisal, $nextState, $user, $request->input('supervisor_comment'));
            } elseif ($appraisal->status === 'counter_sign') {
                $this->appraisalService->transitionState($appraisal, 'completed', $user, $request->input('counter_signing_comment'));
            }
        }

        $appraisal->save();

        $message = $action === 'submit' ? 'Appraisal submitted successfully.' : 'Appraisal saved successfully.';

        return redirect()->route('appraisals.show', $appraisal)->with('success', $message);
    }

    public function print(Appraisal $appraisal)
    {
        $this->authorizeView($appraisal);
        $this->appraisalService->initializeDefaultCompetenciesAndOperations($appraisal);

        $appraisal->load([
            'employee:id,surname,firstname,othername,designation,ippis_no,email,phone,department_id',
            'employee.department:id,name',
            'supervisor:id,surname,firstname,othername,designation,ippis_no,email,phone,department_id',
            'supervisor.department:id,name',
            'counterSigningOfficer:id,surname,firstname,othername,designation,ippis_no,email,phone,department_id',
            'counterSigningOfficer.department:id,name',
            'period:id,name,start_date,end_date',
            'goals.keyResultArea:id,name',
            'competencies',
            'operations',
        ]);

        return Inertia::render('Appraisals/Print', [
            'appraisal' => $appraisal,
            'ratingScale' => Appraisal::RATING_VALUES,
            'ratingLabels' => Appraisal::RATING_LABELS,
        ]);
    }

    public function deleteGoal(Appraisal $appraisal, AppraisalGoal $goal)
    {
        if ($goal->appraisal_id !== $appraisal->id) {
            abort(404);
        }

        if (!$appraisal->canBeEditedBy(request()->user())) {
            return back()->with('error', 'Cannot delete goals in the current appraisal state.');
        }

        $goal->delete();

        $this->appraisalService->calculateAppraisalScores($appraisal);

        return back()->with('success', 'Goal removed successfully.');
    }

    private function authorizeView(Appraisal $appraisal): void
    {
        $user = request()->user();

        if ($user->isAdmin()) return;

        $authorized = $appraisal->employee_id === $user->id
            || $appraisal->supervisor_id === $user->id
            || $appraisal->counter_signing_officer_id === $user->id
            || ($user->isDepartmentHead() && $appraisal->employee->department_id === $user->department_id);

        if (!$authorized) {
            abort(403, 'You are not authorized to view this appraisal.');
        }
    }
}
