<?php

namespace App\Services;

use App\Models\Employee;
use App\Models\PayrollVoucher;
use App\Support\PayrollVoucherOptions;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Support\Collection;

class BankTransferLetterService
{
    public function __construct(private PayrollSheetService $sheetService) {}

    public function normalizeFilters(array $input): array
    {
        $voucherType = trim((string) ($input['voucher_type'] ?? ''));

        return [
            'salary_month'          => trim((string) ($input['salary_month'] ?? '')),
            'voucher_type'          => array_key_exists($voucherType, PayrollVoucherOptions::types()) ? $voucherType : '',
            'voucher_id'            => (int) ($input['voucher_id'] ?? 0),
            'department'            => trim((string) ($input['department'] ?? '')),
            'designation'           => trim((string) ($input['designation'] ?? '')),
            'project'               => trim((string) ($input['project'] ?? '')),
            'branch'                => trim((string) ($input['branch'] ?? '')),
            'religion'              => trim((string) ($input['religion'] ?? '')),
            'salary_payment_method' => trim((string) ($input['salary_payment_method'] ?? '')),
            'employee_id'           => (int) ($input['employee_id'] ?? 0),
        ];
    }

    public function hasActiveFilters(array $filters): bool
    {
        foreach ($filters as $key => $value) {
            if ($key === 'voucher_id' || $key === 'employee_id') {
                if ((int) $value > 0) {
                    return true;
                }
                continue;
            }

            if (trim((string) $value) !== '') {
                return true;
            }
        }

        return false;
    }

    public function salaryMonthOptions(int $companyId): array
    {
        return PayrollVoucher::withoutGlobalScopes()
            ->where('company_id', $companyId)
            ->where('status', 'approved')
            ->select('payroll_year', 'payroll_month')
            ->distinct()
            ->orderByDesc('payroll_year')
            ->orderByDesc('payroll_month')
            ->get()
            ->mapWithKeys(fn ($row) => [
                PayrollVoucherOptions::periodLabel($row->payroll_year, $row->payroll_month)
                    => PayrollVoucherOptions::periodLabel($row->payroll_year, $row->payroll_month),
            ])
            ->all();
    }

    public function voucherNumberOptions(int $companyId, array $filters): array
    {
        $query = PayrollVoucher::withoutGlobalScopes()
            ->where('company_id', $companyId)
            ->where('status', 'approved')
            ->orderByDesc('payroll_year')
            ->orderByDesc('payroll_month')
            ->orderByDesc('id');

        if ($filters['voucher_type'] !== '') {
            $query->where('voucher_type', $filters['voucher_type']);
        }

        if ($period = $this->parseSalaryMonth($filters['salary_month'])) {
            $query->where('payroll_year', $period['year'])
                ->where('payroll_month', $period['month']);
        }

        return $query->get()
            ->mapWithKeys(fn (PayrollVoucher $voucher) => [
                $voucher->id => $voucher->voucher_no . ' — ' . $voucher->periodLabel(),
            ])
            ->all();
    }

    public function employeeRows(int $companyId, array $filters): Collection
    {
        if (!$this->hasActiveFilters($filters)) {
            return collect();
        }

        $voucherType = $filters['voucher_type'] !== '' ? $filters['voucher_type'] : 'salary_sheet';
        $voucher = $this->resolveVoucher($companyId, $filters);

        $sheetFilters = $this->sheetFilters($companyId, $filters, $voucher);

        return $this->employeesQuery($companyId, $filters, $sheetFilters)
            ->get()
            ->map(function (Employee $employee) use ($voucherType, $voucher, $sheetFilters) {
                $amounts = $this->sheetService->amountsForEmployee($employee, $voucherType);
                $amount = $voucherType === 'salary_sheet' ? $amounts['net'] : $amounts['earnings'];

                return [
                    'employee' => $employee,
                    'amount'   => round((float) $amount, 2),
                    'period'   => $voucher?->periodLabel() ?? ($sheetFilters['period_label'] ?? ''),
                ];
            })
            ->filter(fn (array $row) => $row['amount'] > 0)
            ->values();
    }

    public function buildLetter(int $companyId, array $filters, array $employeeIds): array
    {
        $filters['employee_id'] = 0;
        $rows = $this->employeeRows($companyId, $filters)
            ->filter(fn (array $row) => in_array($row['employee']->id, $employeeIds, true))
            ->values();

        $voucher = $this->resolveVoucher($companyId, $filters);
        $total = round($rows->sum('amount'), 2);

        return [
            'rows'          => $rows->all(),
            'total_amount'  => $total,
            'employee_count'=> $rows->count(),
            'period_label'  => $voucher?->periodLabel() ?? ($filters['salary_month'] ?: '—'),
            'voucher_no'    => $voucher?->voucher_no,
            'voucher_type'  => PayrollVoucherOptions::typeLabel($filters['voucher_type'] ?: 'salary_sheet'),
            'filters'       => $filters,
        ];
    }

    private function employeesQuery(int $companyId, array $filters, array $sheetFilters): Builder
    {
        $query = $this->sheetService->employeesQuery($companyId, $sheetFilters)
            ->with(['salaryLines.salaryComponent']);

        if ($filters['salary_payment_method'] !== '') {
            $query->where('salary_payment_method', $filters['salary_payment_method']);
        }

        if ($filters['employee_id'] > 0) {
            $query->where('id', $filters['employee_id']);
        }

        return $query;
    }

    private function sheetFilters(int $companyId, array $filters, ?PayrollVoucher $voucher): array
    {
        if ($voucher) {
            return [
                'voucher_type'  => $voucher->voucher_type,
                'payroll_year'  => $voucher->payroll_year,
                'payroll_month' => $voucher->payroll_month,
                'department'    => $filters['department'] !== '' ? $filters['department'] : ($voucher->department ?? ''),
                'designation'   => $filters['designation'] !== '' ? $filters['designation'] : ($voucher->designation ?? ''),
                'project'       => $filters['project'] !== '' ? $filters['project'] : ($voucher->project ?? ''),
                'branch'        => $filters['branch'] !== '' ? $filters['branch'] : ($voucher->branch ?? ''),
                'religion'      => $filters['religion'] !== '' ? $filters['religion'] : ($voucher->religion ?? ''),
                'period_label'  => $voucher->periodLabel(),
            ];
        }

        $period = $this->parseSalaryMonth($filters['salary_month']);

        return [
            'voucher_type'  => $filters['voucher_type'] !== '' ? $filters['voucher_type'] : 'salary_sheet',
            'payroll_year'  => $period['year'] ?? (int) date('Y'),
            'payroll_month' => $period['month'] ?? (int) date('n'),
            'department'    => $filters['department'],
            'designation'   => $filters['designation'],
            'project'       => $filters['project'],
            'branch'        => $filters['branch'],
            'religion'      => $filters['religion'],
            'period_label'  => $filters['salary_month'],
        ];
    }

    private function resolveVoucher(int $companyId, array $filters): ?PayrollVoucher
    {
        if ($filters['voucher_id'] > 0) {
            $voucher = PayrollVoucher::withoutGlobalScopes()->find($filters['voucher_id']);

            if ($voucher && $voucher->company_id === $companyId && $voucher->status === 'approved') {
                return $voucher;
            }
        }

        $query = PayrollVoucher::withoutGlobalScopes()
            ->where('company_id', $companyId)
            ->where('status', 'approved')
            ->orderByDesc('id');

        if ($filters['voucher_type'] !== '') {
            $query->where('voucher_type', $filters['voucher_type']);
        }

        if ($period = $this->parseSalaryMonth($filters['salary_month'])) {
            $query->where('payroll_year', $period['year'])
                ->where('payroll_month', $period['month']);
        }

        return $query->first();
    }

    private function parseSalaryMonth(string $salaryMonth): ?array
    {
        if (!preg_match('/^([A-Za-z]{3})-(\d{4})$/', $salaryMonth, $matches)) {
            return null;
        }

        $month = array_search($matches[1], PayrollVoucherOptions::months(), true);
        if (!$month) {
            return null;
        }

        return ['year' => (int) $matches[2], 'month' => (int) $month];
    }
}
