<?php

namespace Modules\ExternalSystem\Services;

use Illuminate\Support\Str;
use Modules\Auth\Entities\User;
use Modules\ExternalSystem\Entities\ExternalSystem;
use Modules\ExternalSystem\Exceptions\ExternalSystemLaunchException;
use Modules\ExternalSystem\Support\JwtSigner;

class ExternalSystemLaunchService
{
    /**
     * @return array{launch_url: string, expires_at: string}
     */
    public function launch(User $user, string $code): array
    {
        $system = $this->resolveSystem($code);
        $this->assertSystemAvailable($system);
        $this->assertUserEligible($user, $system);

        if (! $system->sso_enabled) {
            throw new ExternalSystemLaunchException(
                'Sistem luaran tidak menyokong SSO.',
                'external_system_sso_disabled',
                422,
            );
        }

        if (blank($system->sso_secret)) {
            throw new ExternalSystemLaunchException(
                'Sistem luaran belum dikonfigurasi untuk SSO.',
                'external_system_sso_not_configured',
                503,
            );
        }

        $ttl = $system->sso_token_ttl ?: 120;
        $issuedAt = now();
        $expiresAt = $issuedAt->copy()->addSeconds($ttl);

        $payload = [
            'iss' => config('externalsystem.issuer', config('app.name', 'mykopkb')),
            'aud' => $system->sso_audience ?: $system->code,
            'sub' => $user->id,
            'jti' => (string) Str::uuid(),
            'iat' => $issuedAt->timestamp,
            'nbf' => $issuedAt->timestamp,
            'exp' => $expiresAt->timestamp,
            'ic_number' => $user->ic_number,
            'member_number' => $user->member_number,
        ];

        $token = JwtSigner::sign($payload, $system->sso_secret);
        $launchPath = $system->sso_launch_path ?: '/sso/login';
        $launchUrl = rtrim($system->url, '/').'/'.ltrim($launchPath, '/');
        $launchUrl .= '?token='.urlencode($token);

        return [
            'launch_url' => $launchUrl,
            'expires_at' => $expiresAt->toIso8601String(),
        ];
    }

    protected function resolveSystem(string $code): ExternalSystem
    {
        $system = ExternalSystem::query()->where('code', $code)->first();

        if (! $system) {
            throw new ExternalSystemLaunchException(
                'Sistem luaran tidak dijumpai.',
                'external_system_not_found',
                404,
            );
        }

        return $system;
    }

    protected function assertSystemAvailable(ExternalSystem $system): void
    {
        if (! $system->is_active) {
            throw new ExternalSystemLaunchException(
                'Sistem luaran tidak aktif.',
                'external_system_inactive',
                403,
            );
        }

        $now = now();

        if ($system->starts_at?->isAfter($now)) {
            throw new ExternalSystemLaunchException(
                'Sistem luaran belum tersedia.',
                'external_system_upcoming',
                403,
            );
        }

        if ($system->ends_at?->isBefore($now)) {
            throw new ExternalSystemLaunchException(
                'Tempoh akses sistem luaran telah tamat.',
                'external_system_ended',
                403,
            );
        }
    }

    protected function assertUserEligible(User $user, ExternalSystem $system): void
    {
        if ($user->status !== 'active') {
            throw new ExternalSystemLaunchException(
                'Hanya anggota aktif boleh membuka sistem luaran.',
                'external_system_user_inactive',
                403,
            );
        }

        if (blank($user->ic_number)) {
            throw new ExternalSystemLaunchException(
                'Nombor kad pengenalan diperlukan sebelum membuka sistem luaran.',
                'external_system_ic_required',
                422,
            );
        }

        if (blank($user->member_number)) {
            throw new ExternalSystemLaunchException(
                'Nombor anggota diperlukan sebelum membuka sistem luaran.',
                'external_system_member_number_required',
                422,
            );
        }

        if ($system->require_onboarding && blank($user->onboarding_completed_at)) {
            throw new ExternalSystemLaunchException(
                'Sila lengkapkan profil anda sebelum membuka sistem luaran.',
                'external_system_profile_incomplete',
                422,
            );
        }
    }
}
