<?php

declare(strict_types=1);

namespace App\Support;

use Core\RequestLimits;

final class AdmissionForm
{

    public static function maxUploadBytes(): int
    {
        return RequestLimits::uploadMaxFileBytes();
    }

    public static function maxUploadLabel(): string
    {
        return RequestLimits::uploadMaxFileLabel();
    }

    public static function postMaxBytes(): int
    {
        return RequestLimits::postMaxBytes();
    }

    public static function postMaxLabel(): string
    {
        return RequestLimits::postMaxLabel();
    }

    /**
     * @return list<string>
     */
    public static function attachmentFields(): array
    {
        return [
            'profile_photo',
            ...self::documentAttachmentFields(),
        ];
    }

    /**
     * @return list<string>
     */
    public static function documentAttachmentFields(): array
    {
        return [
            'rg_front',
            'rg_back',
            'cref_document',
            'mei_certificate',
            'marriage_certificate',
            'divorce_annotation',
            'work_card',
            'residence_proof',
        ];
    }

    /**
     * @return list<string>
     */
    public static function profilePhotoMimeTypes(): array
    {
        return ['image/jpeg', 'image/png'];
    }

    /**
     * @return list<string>
     */
    public static function documentMimeTypes(): array
    {
        return ['application/pdf'];
    }

    /**
     * @return list<string>
     */
    public static function mimeTypesForLabel(string $labelKey): array
    {
        return $labelKey === 'profile_photo'
            ? self::profilePhotoMimeTypes()
            : self::documentMimeTypes();
    }

    public static function acceptAttributeForLabel(string $labelKey): string
    {
        return $labelKey === 'profile_photo' ? '.jpg,.jpeg,.png' : '.pdf';
    }

    public static function inputAcceptAttributeForLabel(string $labelKey): string
    {
        return $labelKey === 'profile_photo' ? '.jpg,.jpeg,.png' : '.pdf,.jpg,.jpeg,.png';
    }

    public static function normalizeDigits(mixed $value): string
    {
        return preg_replace('/\D/', '', (string) $value) ?? '';
    }

    public static function normalizeNullableString(mixed $value): ?string
    {
        $value = trim((string) $value);
        return $value === '' ? null : $value;
    }

    public static function normalizeUpperState(mixed $value): ?string
    {
        $value = self::normalizeNullableString($value);
        return $value === null ? null : strtoupper($value);
    }

    public static function normalizeMoney(mixed $value): ?string
    {
        $value = preg_replace('/\s+/', '', (string) $value) ?? '';
        if ($value === '') {
            return null;
        }

        if (str_contains($value, ',') && str_contains($value, '.')) {
            $normalized = str_replace('.', '', $value);
            $normalized = str_replace(',', '.', $normalized);
        } else {
            $normalized = str_replace(',', '.', $value);
        }

        if (!is_numeric($normalized)) {
            return null;
        }

        return number_format((float) $normalized, 2, '.', '');
    }

    public static function resolveBankPaymentMethod(array $input): string
    {
        return in_array((string) ($input['bank_payment_method'] ?? 'bank'), ['bank', 'pix'], true)
            ? (string) ($input['bank_payment_method'] ?? 'bank')
            : 'bank';
    }

    public static function usesTransportVoucher(array $input): bool
    {
        return (int) ($input['uses_transport_voucher'] ?? 0) === 1;
    }

    public static function hasDependents(array $input): bool
    {
        return (int) ($input['has_dependents'] ?? 0) === 1;
    }

    /**
     * @return list<array>
     */
    public static function dependentEntries(array $input): array
    {
        if (!self::hasDependents($input) || !isset($input['dependents']) || !is_array($input['dependents'])) {
            return [];
        }

        return array_values(array_filter($input['dependents'], static fn (mixed $dependent): bool => is_array($dependent)));
    }

    /**
     * @return array<string, mixed>
     */
    public static function buildPublicPayload(array $input, array $server, string $cpf): array
    {
        $payload = self::buildBasePayload($input, $cpf);

        return array_merge($payload, [
            'consent' => 1,
            'employment_function' => null,
            'admission_date' => null,
            'dismissal_date' => null,
            'workload_hours' => null,
            'salary_amount' => null,
            'salary_type' => null,
            'bank_payment_method' => 'bank',
            'bank_agency' => null,
            'bank_account' => null,
            'pix_key' => null,
            'status' => 'recebido',
            'internal_notes' => null,
            'lgpd_consent_at' => date('Y-m-d H:i:s'),
            'submitted_ip' => $server['REMOTE_ADDR'] ?? null,
        ]);
    }

    /**
     * @return array<string, mixed>
     */
    public static function buildAdminPayload(array $input, string $cpf): array
    {
        $bankPaymentMethod = self::resolveBankPaymentMethod($input);
        $payload = self::buildBasePayload($input, $cpf);

        return array_merge($payload, [
            'employment_function' => self::normalizeNullableString($input['employment_function'] ?? null),
            'admission_date' => self::normalizeNullableString($input['admission_date'] ?? null),
            'dismissal_date' => self::normalizeNullableString($input['dismissal_date'] ?? null),
            'workload_hours' => self::normalizeNullableString($input['workload_hours'] ?? null),
            'salary_amount' => self::normalizeMoney($input['salary_amount'] ?? null),
            'salary_type' => self::normalizeNullableString($input['salary_type'] ?? null),
            'bank_payment_method' => $bankPaymentMethod,
            'bank_agency' => $bankPaymentMethod === 'bank' ? self::normalizeNullableString($input['bank_agency'] ?? null) : null,
            'bank_account' => $bankPaymentMethod === 'bank' ? self::normalizeNullableString($input['bank_account'] ?? null) : null,
            'pix_key' => $bankPaymentMethod === 'pix' ? self::normalizeNullableString($input['pix_key'] ?? null) : null,
            'status' => (string) ($input['status'] ?? 'recebido'),
            'internal_notes' => self::normalizeNullableString($input['internal_notes'] ?? null),
        ]);
    }

    /**
     * @return array<string, mixed>
     */
    private static function buildBasePayload(array $input, string $cpf): array
    {
        $usesTransportVoucher = self::usesTransportVoucher($input);

        return [
            'race' => (string) ($input['race'] ?? ''),
            'unit_name' => (string) ($input['unit_name'] ?? ''),
            'job_title' => (string) ($input['job_title'] ?? ''),
            'full_name' => (string) ($input['full_name'] ?? ''),
            'father_name' => self::normalizeNullableString($input['father_name'] ?? null),
            'mother_name' => (string) ($input['mother_name'] ?? ''),
            'birth_date' => (string) ($input['birth_date'] ?? ''),
            'marital_status' => (string) ($input['marital_status'] ?? ''),
            'is_student' => (int) ($input['is_student'] ?? 0),
            'education_level' => (string) ($input['education_level'] ?? ''),
            'nationality' => (string) ($input['nationality'] ?? ''),
            'place_of_birth' => self::normalizeNullableString($input['place_of_birth'] ?? null),
            'personal_email' => (string) ($input['personal_email'] ?? ''),
            'phone' => self::normalizeDigits($input['phone'] ?? ''),
            'emergency_contact' => self::normalizeDigits($input['emergency_contact'] ?? ''),
            'address_line' => (string) ($input['address_line'] ?? ''),
            'address_number' => (string) ($input['address_number'] ?? ''),
            'neighborhood' => (string) ($input['neighborhood'] ?? ''),
            'zip_code' => self::normalizeDigits($input['zip_code'] ?? ''),
            'city' => (string) ($input['city'] ?? ''),
            'address_extra' => self::normalizeNullableString($input['address_extra'] ?? null),
            'state' => self::normalizeUpperState($input['state'] ?? ''),
            'rg_number' => self::normalizeDigits($input['rg_number'] ?? ''),
            'rg_issue_date' => (string) ($input['rg_issue_date'] ?? ''),
            'rg_issuer' => (string) ($input['rg_issuer'] ?? ''),
            'birth_city' => (string) ($input['birth_city'] ?? ''),
            'birth_state' => self::normalizeUpperState($input['birth_state'] ?? ($input['state'] ?? '')),
            'cpf' => $cpf,
            'pis_number' => self::normalizeDigits($input['pis_number'] ?? ''),
            'pis_issue_date' => (string) ($input['pis_issue_date'] ?? ''),
            'has_dependents' => self::hasDependents($input) ? 1 : 0,
            'dependent_has_disability' => (int) ($input['dependent_has_disability'] ?? 0),
            'uses_transport_voucher' => $usesTransportVoucher ? 1 : 0,
            'transport_voucher_daily_value' => $usesTransportVoucher
                ? self::normalizeMoney($input['transport_voucher_daily_value'] ?? null)
                : null,
            'uniform_size' => self::normalizeNullableString($input['uniform_size'] ?? null),
            'cref_number' => self::normalizeNullableString($input['cref_number'] ?? null),
            'professor_mei_cnpj' => self::normalizeNullableString($input['professor_mei_cnpj'] ?? null) !== null
                ? self::normalizeDigits($input['professor_mei_cnpj'] ?? '')
                : null,
        ];
    }

    public static function dependentCertificateLabel(int $index): string
    {
        return 'dependent_birth_certificate_' . $index;
    }

    /**
     * @return ?array{name:string,type:string,tmp_name:string,error:int,size:int}
     */
    public static function extractNestedUpload(?array $filesField, int $index): ?array
    {
        if (!is_array($filesField) || !isset($filesField['name'][$index])) {
            return null;
        }

        return [
            'name' => $filesField['name'][$index] ?? '',
            'type' => $filesField['type'][$index] ?? '',
            'tmp_name' => $filesField['tmp_name'][$index] ?? '',
            'error' => $filesField['error'][$index] ?? UPLOAD_ERR_NO_FILE,
            'size' => $filesField['size'][$index] ?? 0,
        ];
    }
}
