<?php

namespace App\Http\Controllers\Company\Payroll;

use App\Http\Controllers\Controller;
use App\Models\{AuditLog, PayrollSalaryComponent, Setting};
use App\Support\{CoaParentPickerBuilder, SalaryComponentAccountQuickAdd, SalaryComponentOptions};
use Illuminate\Http\Request;
use Illuminate\Validation\Rule;

class PayrollSalaryComponentsController extends Controller
{
    public function index(Request $request)
    {
        $this->ensurePayrollModule();
        $this->gate('view');

        $cid = auth()->user()->company_id;
        $query = PayrollSalaryComponent::withoutGlobalScopes()
            ->where('company_id', $cid)
            ->with(['expenseAccount', 'liabilityAccount']);

        if ($request->filled('search')) {
            $search = $request->search;
            $query->where('name', 'like', "%{$search}%");
        }
        if ($request->filled('type')) {
            $query->where('type', $request->type);
        }
        if ($request->filled('sub_type')) {
            $query->where('sub_type', $request->sub_type);
        }
        if ($request->filled('status')) {
            $query->where('is_active', $request->status === 'active');
        }

        $components = $query->orderBy('type')->orderBy('name')->paginate(25)->withQueryString();
        $stats = [
            'total'  => PayrollSalaryComponent::withoutGlobalScopes()->where('company_id', $cid)->count(),
            'active' => PayrollSalaryComponent::withoutGlobalScopes()->where('company_id', $cid)->where('is_active', true)->count(),
        ];

        $accountTrees = SalaryComponentAccountQuickAdd::salaryComponentAccountTrees($cid);
        $canCreateCoaAccount = auth()->user()->hasPermission('accounts', 'create');
        $coaQuickAddSections = [
            'expense'         => SalaryComponentAccountQuickAdd::sectionsForListKey('expense'),
            'liability'       => SalaryComponentAccountQuickAdd::sectionsForListKey('liability'),
            'deductionCredit' => SalaryComponentAccountQuickAdd::sectionsForListKey('deductionCredit'),
        ];
        $parentPickerTree = CoaParentPickerBuilder::build($cid);
        $parentPickerAccounts = CoaParentPickerBuilder::accountsMap($cid);

        return view('payroll.salary-components.index', compact(
            'components',
            'stats',
            'accountTrees',
            'canCreateCoaAccount',
            'coaQuickAddSections',
            'parentPickerTree',
            'parentPickerAccounts',
        ));
    }

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

        $validated = $this->validateComponent($request);
        $record = PayrollSalaryComponent::withoutGlobalScopes()->create(array_merge($validated, [
            'company_id' => auth()->user()->company_id,
        ]));

        AuditLog::record('create', 'payroll_salary_components', (string) $record->id, null, ['name' => $record->name], "Salary component created: {$record->name}");

        return back()->with('success', "Salary component '{$record->name}' created.");
    }

    public function update(Request $request, PayrollSalaryComponent $salaryComponent)
    {
        $this->ensurePayrollModule();
        $this->gate('edit');
        $this->sameCompany($salaryComponent);

        $validated = $this->validateComponent($request, $salaryComponent);
        $salaryComponent->update($validated);

        AuditLog::record('update', 'payroll_salary_components', (string) $salaryComponent->id, null, $validated, "Salary component updated: {$salaryComponent->name}");

        return back()->with('success', "Salary component '{$salaryComponent->name}' updated.");
    }

    public function toggle(PayrollSalaryComponent $salaryComponent)
    {
        $this->ensurePayrollModule();
        $this->gate('edit');
        $this->sameCompany($salaryComponent);

        $salaryComponent->update(['is_active' => !$salaryComponent->is_active]);

        return back()->with('success', 'Salary component marked as ' . ($salaryComponent->is_active ? 'active' : 'inactive') . '.');
    }

    public function destroy(PayrollSalaryComponent $salaryComponent)
    {
        $this->ensurePayrollModule();
        $this->gate('edit');
        $this->sameCompany($salaryComponent);

        $name = $salaryComponent->name;
        $id = $salaryComponent->id;
        $salaryComponent->delete();

        AuditLog::record('delete', 'payroll_salary_components', (string) $id, null, null, "Salary component deleted: {$name}");

        return back()->with('success', "Salary component '{$name}' deleted.");
    }

    private function validateComponent(Request $request, ?PayrollSalaryComponent $component = null): array
    {
        $cid = auth()->user()->company_id;
        $type = $request->input('type');
        $subType = $request->input('sub_type');
        $needsExpense = $type === 'earning';

        $validated = $request->validate([
            'name' => [
                'required', 'string', 'max:120',
                Rule::unique('payroll_salary_components')
                    ->where(fn ($q) => $q->where('company_id', $cid)->where('type', $type))
                    ->ignore($component?->id),
            ],
            'type' => 'required|in:earning,deduction',
            'sub_type' => [
                'required', 'string',
                Rule::in(array_keys(SalaryComponentOptions::subTypes((string) $type))),
            ],
            'expense_account_id' => [
                Rule::requiredIf($needsExpense),
                'nullable', 'integer',
                Rule::exists('accounts', 'id')->where(fn ($q) => $q
                    ->where('company_id', $cid)
                    ->where('is_group', false)
                    ->where('type', 'expense')),
            ],
            'liability_account_id' => [
                'required', 'integer',
                Rule::exists('accounts', 'id')->where(fn ($q) => $q
                    ->where('company_id', $cid)
                    ->where('is_group', false)
                    ->whereIn('type', $type === 'deduction' ? ['income', 'liability'] : ['liability'])),
            ],
            'is_inactive' => 'nullable|boolean',
        ]);

        return [
            'name'                 => $validated['name'],
            'type'                 => $validated['type'],
            'sub_type'             => $validated['sub_type'],
            'expense_account_id'   => $needsExpense ? ($validated['expense_account_id'] ?? null) : null,
            'liability_account_id' => $validated['liability_account_id'],
            'is_active'            => !$request->boolean('is_inactive'),
        ];
    }

    private function ensurePayrollModule(): void
    {
        if (Setting::get(auth()->user()->company_id, 'use_payroll_module', '0') !== '1') {
            abort(404);
        }
    }

    private function gate(string $action = 'view'): void
    {
        if (!auth()->user()->hasPermission('payroll', $action)) {
            abort(403);
        }
    }

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