<?php

namespace App\Services;

use App\Models\Customer;
use Illuminate\Support\Facades\Http;
use Illuminate\Support\Str;

class KycVerificationService
{
    public function apply(Customer $customer): void
    {
        if ($customer->kyc_status === 'rejected') {
            return;
        }

        if ($this->provider($customer) === 'didit') {
            return;
        }

        if (! $this->hasRequiredProfile($customer) || ! $this->hasValidIdentityNumber($customer)) {
            return;
        }

        $wasVerified = $customer->kyc_status === 'verified';

        $customer->forceFill([
            'kyc_status' => 'verified',
            'kyc_verified_at' => $customer->kyc_verified_at ?? now(),
            'kyc_locked_at' => $customer->kyc_locked_at ?? now(),
            'bvn_verified_at' => $this->isElevenDigits($customer->bvn) ? ($customer->bvn_verified_at ?? now()) : $customer->bvn_verified_at,
            'nin_verified_at' => $this->isElevenDigits($customer->nin) ? ($customer->nin_verified_at ?? now()) : $customer->nin_verified_at,
            'kyc_verification_method' => $customer->kyc_verification_method ?? 'automatic_profile_identity_check',
            'kyc_provider' => $customer->kyc_provider ?? 'local',
            'kyc_verification_notes' => 'Automatically verified because the member profile has complete bio-data plus a valid 11-digit BVN or NIN.',
        ])->save();

        if (! $wasVerified) {
            ActivityLogger::log('member_kyc_verified', $customer->fullName().' KYC verified by local profile check.', $customer);
        }
    }

    /**
     * @return array{successful: bool, message: string, url?: string}
     */
    public function createHostedSession(Customer $customer, ?string $callbackUrl = null): array
    {
        $customer->loadMissing('tenant');

        if ($customer->identityFieldsLocked()) {
            return ['successful' => false, 'message' => 'This member has already been verified and locked.'];
        }

        $settings = $this->settings($customer);

        if ($settings['provider'] !== 'didit') {
            return ['successful' => false, 'message' => 'Didit is not selected in Settings > KYC.'];
        }

        if (! $settings['api_key'] || ! $settings['workflow_id']) {
            return ['successful' => false, 'message' => 'Add the Didit API key and KYC workflow ID in Settings > KYC.'];
        }

        $response = Http::withHeaders(['x-api-key' => $settings['api_key']])
            ->acceptJson()
            ->timeout(30)
            ->post($settings['base_url'].'/v3/session/', [
                'workflow_id' => $settings['workflow_id'],
                'vendor_data' => 'tenant-'.$customer->tenant_id.'-member-'.$customer->id,
                'callback' => $callbackUrl,
                'callback_method' => 'both',
                'metadata' => json_encode([
                    'tenant_id' => $customer->tenant_id,
                    'member_id' => $customer->id,
                    'account_number' => $customer->account_number,
                ]),
                'language' => 'en',
                'contact_details' => [
                    'email' => $customer->email,
                    'send_notification_emails' => false,
                    'email_lang' => 'en',
                    'phone' => $customer->phone,
                ],
                'expected_details' => [
                    'first_name' => $customer->first_name,
                    'last_name' => $customer->last_name,
                    'date_of_birth' => $customer->date_of_birth?->format('Y-m-d'),
                    'gender' => $customer->gender ? strtoupper(Str::substr($customer->gender, 0, 1)) : null,
                    'nationality' => 'NGA',
                    'id_country' => 'NGA',
                    'poa_country' => 'NGA',
                    'address' => $customer->address,
                    'identification_number' => $customer->nin ?: ($customer->id_number ?: $customer->bvn),
                ],
            ]);

        if (! $response->successful()) {
            $customer->forceFill([
                'kyc_provider' => 'didit',
                'kyc_provider_status' => 'failed_to_create_session',
                'kyc_provider_response' => $response->json() ?: ['body' => Str::limit($response->body(), 1000)],
            ])->save();

            return ['successful' => false, 'message' => 'Didit could not create a verification session. Check the KYC credentials and workflow ID.'];
        }

        $payload = $response->json();
        $sessionId = (string) ($payload['session_id'] ?? '');
        $url = (string) ($payload['url'] ?? '');

        $customer->forceFill([
            'kyc_provider' => 'didit',
            'kyc_provider_session_id' => $sessionId ?: $customer->kyc_provider_session_id,
            'kyc_provider_status' => (string) ($payload['status'] ?? 'Not Started'),
            'kyc_provider_url' => $url ?: null,
            'kyc_provider_response' => $payload,
            'kyc_verification_method' => 'didit_hosted_session',
        ])->save();

        if ($url === '') {
            return ['successful' => false, 'message' => 'Didit created a session but did not return a verification URL.'];
        }

        return ['successful' => true, 'message' => 'Didit verification session created.', 'url' => $url];
    }

    /**
     * @return array{successful: bool, message: string, status?: string}
     */
    public function syncHostedSession(Customer $customer, ?string $sessionId = null, ?string $status = null): array
    {
        $customer->loadMissing('tenant');
        $settings = $this->settings($customer);
        $sessionId = $sessionId ?: $customer->kyc_provider_session_id;
        $payload = [];

        if (! $sessionId) {
            return ['successful' => false, 'message' => 'No Didit session has been linked to this member.'];
        }

        if ($settings['api_key']) {
            $response = Http::withHeaders(['x-api-key' => $settings['api_key']])
                ->acceptJson()
                ->timeout(30)
                ->get($settings['base_url'].'/v3/session/'.$sessionId.'/decision/');

            if ($response->successful()) {
                $payload = $response->json() ?: [];
                $status = (string) ($payload['status'] ?? $status);
            }
        }

        $status = $status ?: $customer->kyc_provider_status;
        $updates = [
            'kyc_provider' => 'didit',
            'kyc_provider_session_id' => $sessionId,
            'kyc_provider_status' => $status,
        ];

        if ($payload !== []) {
            $updates['kyc_provider_response'] = $payload;
        }

        if ($status === 'Approved') {
            $updates = [
                ...$updates,
                'kyc_status' => 'verified',
                'kyc_verified_at' => $customer->kyc_verified_at ?? now(),
                'kyc_locked_at' => $customer->kyc_locked_at ?? now(),
                'kyc_verification_method' => 'didit_hosted_session',
                'kyc_verification_notes' => 'Identity verification approved by Didit hosted KYC session.',
            ];
        }

        if ($status === 'Declined') {
            $updates = [
                ...$updates,
                'kyc_status' => 'rejected',
                'kyc_verification_method' => 'didit_hosted_session',
                'kyc_verification_notes' => 'Identity verification was declined by Didit.',
            ];
        }

        $customer->forceFill($updates)->save();

        return [
            'successful' => in_array($status, ['Approved', 'In Review', 'Declined', 'In Progress', 'Not Started'], true),
            'message' => 'KYC status synced: '.($status ?: 'Unknown').'.',
            'status' => $status,
        ];
    }

    private function hasRequiredProfile(Customer $customer): bool
    {
        foreach (['first_name', 'last_name', 'phone', 'gender', 'date_of_birth', 'address'] as $field) {
            if (blank($customer->{$field})) {
                return false;
            }
        }

        return true;
    }

    private function hasValidIdentityNumber(Customer $customer): bool
    {
        return $this->isElevenDigits($customer->bvn) || $this->isElevenDigits($customer->nin);
    }

    private function isElevenDigits(?string $value): bool
    {
        return preg_match('/^\d{11}$/', (string) $value) === 1;
    }

    private function provider(Customer $customer): string
    {
        return $this->settings($customer)['provider'];
    }

    /**
     * @return array{provider: string, api_key: ?string, workflow_id: ?string, base_url: string}
     */
    private function settings(Customer $customer): array
    {
        $customer->loadMissing('tenant');
        $settings = $customer->tenant?->settings ?? [];

        return [
            'provider' => strtolower((string) ($settings['kyc_provider'] ?? 'local')),
            'api_key' => filled($settings['didit_api_key'] ?? null) ? (string) $settings['didit_api_key'] : null,
            'workflow_id' => filled($settings['didit_workflow_id'] ?? null) ? (string) $settings['didit_workflow_id'] : null,
            'base_url' => rtrim((string) ($settings['didit_base_url'] ?? 'https://verification.didit.me'), '/'),
        ];
    }
}
