<?php

namespace App\Services\Auth;

use App\Http\Controllers\Saving\SignatureController;
use App\Models\Datmas\Indentitas;
use App\Models\Datmas\Siswa;
use App\Models\Saving\Timagable;
use App\Models\Saving\Tregistrasi;
use App\Models\Saving\Tsignsnk;
use App\Models\Saving\Tsnk;
use Illuminate\Http\UploadedFile;
use Illuminate\Support\Facades\Storage;
use Illuminate\Validation\ValidationException;

class RegistrationService
{
    public function store(string $nouid, array $data, ?UploadedFile $documentFile = null, int|string|null $updatedBy = 0, ?string $ipAddress = null, ?string $userAgent = null): array
    {
        $existingRegistration = Tregistrasi::where('nouid', $nouid)
            ->whereIn('sta', [Tregistrasi::STATUS_REJECTED, Tregistrasi::STATUS_PENDING, Tregistrasi::STATUS_ACCEPTED])
            ->first();

        $agreement = $this->resolveAgreement($nouid, $data);

        $registrationData = [
            'nouid' => $nouid,
            'nama' => $data['nama'],
            'warneg' => $data['warneg'],
            'warneg_name' => $data['warnegName'],
            'nik' => $data['warneg'] === 'ID' ? ($data['nik'] ?? null) : null,
            'kk' => $data['warneg'] === 'ID' ? ($data['kk'] ?? null) : null,
            'paspor' => $data['warneg'] !== 'ID' ? ($data['paspor'] ?? null) : null,
            'alamat1' => $data['alamat1'],
            'alamat2' => (bool) $data['temtin'] ? ($data['alamat2'] ?? null) : null,
            'temtin' => (bool) $data['temtin'],
            'hub' => $data['hub'],
            'tel' => formatPhoneNumber($data['tel']),
            'email' => $data['email'],
            'sta' => Tregistrasi::STATUS_PENDING,
            'updated_by' => $updatedBy ?? 0,
        ];

        if ($existingRegistration && $existingRegistration->sta === Tregistrasi::STATUS_REJECTED) {
            $existingRegistration->update($registrationData);
            $registration = $existingRegistration->fresh();
        } else {
            $registration = Tregistrasi::create($registrationData);
        }

        if ($documentFile) {
            $this->storeDocument($registration, $documentFile, $data['warneg'] === 'ID' ? 'ktp' : 'paspor');
        }

        $this->storeSignature(
            $nouid,
            $agreement['sign'],
            $agreement['payload'],
            $agreement['snk_version'],
            $ipAddress,
            $userAgent,
        );

        return [
            'registration' => $registration,
            'agreement' => $agreement,
        ];
    }

    public function buildAgreementPayload(string $nouid, array $data): array
    {
        $kabupatenName = data_get($data, 'kabName') ?? data_get($data, 'alamat1.kabName');

        if (
            blank($nouid) ||
            blank($data['nama'] ?? null) ||
            blank($data['warneg'] ?? null) ||
            ($data['warneg'] === 'ID' && blank($data['nik'] ?? null)) ||
            ($data['warneg'] !== 'ID' && blank($data['paspor'] ?? null)) ||
            blank($kabupatenName)
        ) {
            throw ValidationException::withMessages([
                'message' => ['Data tidak lengkap untuk memproses persetujuan registrasi.'],
            ]);
        }

        $snk = Tsnk::with(['points' => fn ($query) => $query->orderBy('nmr')])
            ->where('is_active', true)
            ->latest('version')
            ->firstOrFail();

        $siswa = Indentitas::where('nouid', $nouid)->with('siswa')->first()?->siswa
            ?? Siswa::query()
                ->where('nis', data_get($data, 'nis', $nouid))
                ->first();

        if (! $siswa) {
            throw ValidationException::withMessages([
                'nis' => ['Data siswa tidak ditemukan.'],
            ]);
        }

        $signatureData = [
            'nouid' => $nouid,
            'snk_version' => $snk->version,
            'nama' => $data['nama'],
            'id' => $data['warneg'] === 'ID' ? $data['nik'] : $data['paspor'],
            'waktu' => now()->toISOString(),
        ];

        $signature = SignatureController::getSign($signatureData, $nouid);

        if (!isset($signature['sign'])) {
            throw ValidationException::withMessages([
                'message' => ['Gagal menghasilkan tanda tangan digital registrasi.'],
            ]);
        }

        return [
            'payload' => encrypt($signatureData),
            'sign' => $signature['sign'],
            'snk_version' => $snk->version,
            'qr_code_svg' => $signature['qr_code_svg'] ?? null,
            'ortu' => $data['nama'],
            'siswa' => $siswa->namlen,
            'kota' => $kabupatenName . ', ' . now()->translatedFormat('d F Y'),
            'snk' => [
                'version' => $snk->version,
                'effective' => $snk->effective,
                'title' => $snk->title,
                'summary' => $snk->summary,
                'points' => $snk->points->map(fn ($point) => [
                    'nmr' => $point->nmr,
                    'title' => $point->title,
                    'content' => $point->content,
                ]),
            ],
        ];
    }

    protected function resolveAgreement(string $nouid, array $data): array
    {
        if (!empty($data['sign']) && !empty($data['payload'])) {
            try {
                $decryptedPayload = decrypt($data['payload']);
            } catch (\Throwable) {
                throw ValidationException::withMessages([
                    'payload' => ['Payload persetujuan tidak valid.'],
                ]);
            }

            return [
                'sign' => $data['sign'],
                'payload' => $data['payload'],
                'snk_version' => $decryptedPayload['snk_version'] ?? '1.0.0',
            ];
        }

        return $this->buildAgreementPayload($nouid, $data);
    }

    protected function storeDocument(Tregistrasi $registration, UploadedFile $documentFile, string $fileType): void
    {
        $disk = config('filesystems.default');
        $filename = "{$fileType}_{$registration->nouid}_" . time() . '.' . $documentFile->extension();
        $path = $documentFile->storeAs('doc/reg', $filename, $disk);

        $fileData = [
            'name' => $filename,
            'path' => $path,
            'mime_type' => $documentFile->getMimeType(),
            'size' => $documentFile->getSize(),
            'imagable_id' => $registration->id,
            'imagable_type' => $registration::class,
        ];

        $existingFile = Timagable::where('imagable_type', $registration::class)
            ->where('imagable_id', $registration->id)
            ->first();

        if ($existingFile) {
            Storage::disk($disk)->delete($existingFile->path);
            $existingFile->update($fileData);

            return;
        }

        Timagable::create($fileData);
    }

    protected function storeSignature(string $nouid, string $sign, string $payload, string $snkVersion, ?string $ipAddress, ?string $userAgent): void
    {
        Tsignsnk::updateOrCreate(
            ['nouid' => $nouid],
            [
                'sign' => $sign,
                'payload' => $payload,
                'snk_version' => $snkVersion,
                'ip_address' => $ipAddress,
                'user_agent' => $userAgent,
            ]
        );
    }
}
