<?php

namespace App\Services;

use App\Models\Currency;
use App\Models\Employee;
use App\Models\EmployeeSalary;
use App\Models\SalaryComponent;
use App\Models\User;
use Illuminate\Support\Facades\DB;

class MalawiTerritorySalaryService
{
    public const COMPANY_SLUG = MalawiTerritoryRosterSync::COMPANY_SLUG;

    /** @var array<string, SalaryComponent> */
    private array $components = [];

    public function seedForCompany(?User $company = null): array
    {
        $company = $company ?? $this->resolveCompany();
        $stats = ['components' => 0, 'employee_salaries' => 0];

        $this->ensureMalawiCurrency($company);
        $this->seedComponents($company);
        $stats['components'] = count($this->components);
        $stats['employee_salaries'] = $this->syncEmployeeSalaries($company);

        return $stats;
    }

    private function ensureMalawiCurrency(User $company): void
    {
        Currency::where('code', 'MWK')->update(['symbol' => 'MWK']);

        DB::table('settings')->updateOrInsert(
            ['user_id' => $company->id, 'key' => 'defaultCurrency'],
            ['value' => 'MWK', 'updated_at' => now(), 'created_at' => now()]
        );
    }

    public function seedComponents(User $company): void
    {
        $this->components = [];

        foreach (config('malawi_territory_salary.components', []) as $definition) {
            $component = SalaryComponent::updateOrCreate(
                [
                    'created_by' => $company->id,
                    'name' => $definition['name'],
                ],
                [
                    'description' => $definition['description'] ?? null,
                    'type' => $definition['type'],
                    'calculation_type' => $definition['calculation_type'],
                    'default_amount' => $definition['default_amount'] ?? 0,
                    'percentage_of_basic' => $definition['percentage_of_basic'],
                    'is_taxable' => $definition['is_taxable'] ?? false,
                    'is_mandatory' => $definition['is_mandatory'] ?? false,
                    'status' => 'active',
                ]
            );

            $this->components[$definition['name']] = $component;
        }
    }

    public function syncEmployeeSalaries(User $company): int
    {
        if ($this->components === []) {
            $this->loadComponentsFromDatabase($company);
        }

        $synced = 0;

        Employee::where('created_by', $company->id)
            ->where('employee_status', 'active')
            ->with(['user', 'designation'])
            ->each(function (Employee $employee) use ($company, &$synced) {
                if (! $employee->user_id) {
                    return;
                }

                $designation = $employee->designation?->name ?? '';
                $userType = $employee->user?->type ?? 'employee';
                $basicSalary = $this->inferBasicSalary($designation, $userType);
                $componentIds = $this->defaultComponentIds($designation, $userType);

                EmployeeSalary::updateOrCreate(
                    ['employee_id' => $employee->user_id],
                    [
                        'basic_salary' => $basicSalary,
                        'components' => $componentIds,
                        'is_active' => true,
                        'calculation_status' => 'calculated',
                        'notes' => 'Malawi Territory standard salary structure (MWK).',
                        'created_by' => $company->id,
                    ]
                );

                if ($employee->base_salary !== $basicSalary) {
                    $employee->update(['base_salary' => $basicSalary]);
                }

                $synced++;
            });

        return $synced;
    }

    /**
     * @return list<int>
     */
    public function defaultComponentIds(string $designation, string $userType): array
    {
        $mandatory = [
            'Housing Allowance',
            'Transport Allowance',
            'Airtime Allowance',
            'Medical Allowance',
            'PAYE',
            'MASM',
            'Pension (OPSM/MIPF)',
        ];

        $ids = [];
        foreach ($mandatory as $name) {
            if (isset($this->components[$name])) {
                $ids[] = $this->components[$name]->id;
            }
        }

        if ($this->qualifiesForResponsibilityAllowance($designation, $userType)
            && isset($this->components['Responsibility Allowance'])) {
            $ids[] = $this->components['Responsibility Allowance']->id;
        }

        return array_values(array_unique($ids));
    }

    public function inferBasicSalary(string $designation, string $userType): int
    {
        $grades = config('malawi_territory_salary.basic_salary_by_grade', []);
        $grade = $this->inferSalaryGrade($designation, $userType);

        return (int) ($grades[$grade] ?? $grades['mid'] ?? 420000);
    }

    public function inferSalaryGrade(string $designation, string $userType): string
    {
        $designationLower = strtolower($designation);

        if ($userType === 'manager' || preg_match('/\b(manager|secretary|director|funds manager|chief)\b/i', $designation)) {
            return 'manager';
        }

        if (preg_match('/\b(senior|lead|coordinator|accountant)\b/i', $designation)) {
            return 'senior';
        }

        if (preg_match('/\b(guard|cleaner|gardener|assistant cook|intern|driver)\b/i', $designation)) {
            return 'entry';
        }

        return 'mid';
    }

    private function qualifiesForResponsibilityAllowance(string $designation, string $userType): bool
    {
        if ($userType === 'manager') {
            return true;
        }

        return (bool) preg_match('/\b(manager|secretary|coordinator|director|lead|accountant)\b/i', $designation);
    }

    private function loadComponentsFromDatabase(User $company): void
    {
        $this->components = [];
        SalaryComponent::where('created_by', $company->id)
            ->where('status', 'active')
            ->get()
            ->each(fn (SalaryComponent $c) => $this->components[$c->name] = $c);
    }

    private function resolveCompany(): User
    {
        $company = User::where('slug', self::COMPANY_SLUG)->where('type', 'company')->first();
        if (! $company) {
            throw new \RuntimeException('Malawi Territory company not found.');
        }

        return $company;
    }
}
