<?php

namespace App\Http\Controllers\Company\Admin;

use App\Http\Controllers\Controller;
use App\Models\{AuditLog, FiscalYear, Setting};
use App\Services\BooksClosingService;
use Carbon\Carbon;
use Illuminate\Http\Request;
use Illuminate\Validation\Rule;

class FiscalYearsController extends Controller
{
    public function __construct(private readonly BooksClosingService $booksClosing)
    {
    }

    public function index()
    {
        $this->gate('settings', 'view');

        $companyId = auth()->user()->company_id;
        $fiscalYears = FiscalYear::orderBy('start_date', 'desc')->get();
        $currentYear = $fiscalYears->firstWhere('is_current', true);
        $closingDate = $this->booksClosing->closingDate($companyId);
        $suggestedClosingDate = $this->booksClosing->suggestedClosingDate($companyId);
        $hasClosingPassword = $this->booksClosing->hasClosingPassword($companyId);

        return view('admin.fiscal-years.index', compact(
            'fiscalYears',
            'currentYear',
            'closingDate',
            'suggestedClosingDate',
            'hasClosingPassword',
        ));
    }

    public function updateClosing(Request $request)
    {
        $this->gate('settings', 'edit');

        $companyId = auth()->user()->company_id;
        $validated = $request->validate([
            'books_closing_date' => 'nullable|date',
            'closing_password' => 'nullable|string|min:4|max:100',
            'closing_password_confirmation' => 'nullable|same:closing_password',
            'remove_closing_password' => 'nullable|boolean',
        ]);

        if (!empty($validated['closing_password']) && empty($validated['books_closing_date'])) {
            return back()->withErrors([
                'closing_password' => 'Set a closing date before adding a closing password.',
            ]);
        }

        $this->booksClosing->updateClosing($companyId, [
            'date' => $validated['books_closing_date'] ?? '',
            'password' => $validated['closing_password'] ?? null,
            'remove_password' => $request->boolean('remove_closing_password'),
        ], auth()->id());

        return back()->with('success', 'Books closing settings saved.');
    }

    public function create()
    {
        $this->gate('settings', 'edit');

        $companyId  = auth()->user()->company_id;
        $startMonth = (int) Setting::get($companyId, 'fiscal_year_start_month', 1);

        // Suggest next fiscal year start date based on last FY
        $lastFY    = FiscalYear::orderBy('end_date', 'desc')->first();
        $startDate = $lastFY
            ? $lastFY->end_date->copy()->addDay()
            : Carbon::createFromDate(now()->year, $startMonth, 1);

        $endDate = $startDate->copy()->addYear()->subDay();

        return view('admin.fiscal-years.create', compact('startDate', 'endDate'));
    }

    public function store(Request $request)
    {
        $this->gate('settings', 'edit');

        $companyId = auth()->user()->company_id;

        $validated = $request->validate([
            'name'       => [
                'required', 'string', 'max:50',
                Rule::unique('fiscal_years', 'name')
                    ->where(fn($q) => $q->where('company_id', $companyId)),
            ],
            'start_date' => 'required|date',
            'end_date'   => 'required|date|after:start_date',
        ]);

        // Check for date overlaps with existing fiscal years for this company
        $overlap = FiscalYear::where(function ($q) use ($validated) {
            $q->whereBetween('start_date', [$validated['start_date'], $validated['end_date']])
              ->orWhereBetween('end_date',  [$validated['start_date'], $validated['end_date']])
              ->orWhere(function ($q2) use ($validated) {
                  $q2->where('start_date', '<=', $validated['start_date'])
                     ->where('end_date',   '>=', $validated['end_date']);
              });
        })->exists();

        if ($overlap) {
            return back()->withErrors([
                'start_date' => 'These dates overlap with an existing fiscal year.'
            ])->withInput();
        }

        // First fiscal year for this company becomes current automatically
        $isFirst = FiscalYear::count() === 0;

        $fy = FiscalYear::create([
            'company_id' => $companyId,
            'name'       => $validated['name'],
            'start_date' => $validated['start_date'],
            'end_date'   => $validated['end_date'],
            'status'     => 'open',
            'is_current' => $isFirst,
        ]);

        AuditLog::record('create', 'fiscal_year', (string) $fy->id, null,
            ['name' => $fy->name, 'start_date' => $fy->start_date, 'end_date' => $fy->end_date],
            "Fiscal year created: {$fy->name}");

        return redirect()->route('admin.fiscal-years.index')
            ->with('success', "Fiscal year '{$fy->name}' created successfully.");
    }

    public function setCurrent(FiscalYear $fiscalYear)
    {
        $this->gate('settings', 'edit');
        $this->sameCompany($fiscalYear);

        if ($fiscalYear->status === 'locked') {
            return back()->withErrors(['error' => 'Cannot set a locked fiscal year as active.']);
        }

        // Unset current — CompanyScope ensures only this company's FYs are touched
        FiscalYear::where('is_current', true)->update(['is_current' => false]);
        $fiscalYear->update(['is_current' => true]);

        AuditLog::record('update', 'fiscal_year', (string) $fiscalYear->id,
            ['is_current' => false], ['is_current' => true],
            "Fiscal year set as active: {$fiscalYear->name}");

        return back()->with('success', "'{$fiscalYear->name}' is now the active fiscal year.");
    }

    public function lock(FiscalYear $fiscalYear)
    {
        $this->gate('settings', 'edit');
        $this->sameCompany($fiscalYear);

        if ($fiscalYear->is_current) {
            return back()->withErrors(['error' => 'Cannot lock the currently active fiscal year.']);
        }
        if ($fiscalYear->status === 'locked') {
            return back()->withErrors(['error' => 'This fiscal year is already locked.']);
        }

        $fiscalYear->update([
            'status'    => 'locked',
            'closed_at' => now(),
            'closed_by' => auth()->id(),
        ]);

        AuditLog::record('lock', 'fiscal_year', (string) $fiscalYear->id,
            ['status' => 'open'], ['status' => 'locked'],
            "Fiscal year locked: {$fiscalYear->name}");

        return back()->with('success', "Fiscal year '{$fiscalYear->name}' locked successfully.");
    }

    // ── Helpers ───────────────────────────────────────────────────────────────
    private function gate(string $module, string $action): void
    {
        if (!auth()->user()->hasPermission($module, $action)) {
            abort(403, 'Insufficient permissions.');
        }
    }

    private function sameCompany(FiscalYear $fy): void
    {
        if ($fy->company_id !== auth()->user()->company_id) {
            abort(403);
        }
    }
}
