<?php

namespace App\Console\Commands;

use App\Core\Registrar\RegistrarManager;
use App\Jobs\SendEmailJob;
use App\Models\ClientDomain;
use App\Models\Setting;
use Illuminate\Console\Command;
use Illuminate\Support\Facades\Log;

class SyncDomainTransfersCommand extends Command
{
    /**
     * The name and signature of the console command.
     *
     * @var string
     */
    protected $signature = 'domains:sync-transfers
                            {--limit=100 : Maximum number of domains to check}';

    /**
     * The console command description.
     *
     * @var string
     */
    protected $description = 'Check pending domain transfers and update their status from registrar';

    protected RegistrarManager $registrarManager;

    public function __construct(RegistrarManager $registrarManager)
    {
        parent::__construct();
        $this->registrarManager = $registrarManager;
    }

    /**
     * Execute the console command.
     */
    public function handle(): int
    {
        // PRC-318 / D-10 — defensive master toggle. Kernel.php already
        // wraps the schedule in this check, but a manual `artisan
        // domains:sync-transfers` should also honour the toggle.
        if (! (bool) Setting::getValue('domain_sync_enabled', true)) {
            $this->info('Domain sync is disabled (Setting `domain_sync_enabled` is off). Skipping.');
            Log::info('SyncDomainTransfersCommand skipped — domain_sync_enabled=false');
            return Command::SUCCESS;
        }

        $this->info('Checking pending domain transfers...');

        $limit = (int) $this->option('limit');

        $pendingDomains = ClientDomain::with(['tld', 'client'])
            ->where('status', 'pending_transfer')
            ->limit($limit)
            ->get();

        if ($pendingDomains->isEmpty()) {
            $this->info('No pending transfers found.');

            return Command::SUCCESS;
        }

        $this->info("Found {$pendingDomains->count()} pending transfer(s).");

        $stats = [
            'completed' => 0,
            'still_pending' => 0,
            'failed' => 0,
            'skipped' => 0,
        ];

        foreach ($pendingDomains as $clientDomain) {
            try {
                $result = $this->syncTransfer($clientDomain);

                if ($result === 'completed') {
                    $stats['completed']++;
                    $this->line("  <fg=green>[COMPLETED]</> {$clientDomain->domain}");
                } elseif ($result === 'failed') {
                    $stats['failed']++;
                    $this->line("  <fg=red>[FAILED]</> {$clientDomain->domain}");
                } elseif ($result === 'skipped') {
                    $stats['skipped']++;
                    $this->line("  <fg=yellow>[SKIPPED]</> {$clientDomain->domain}");
                } else {
                    $stats['still_pending']++;
                    $this->line("  <fg=blue>[PENDING]</> {$clientDomain->domain}");
                }
            } catch (\Exception $e) {
                $stats['failed']++;
                $this->line("  <fg=red>[ERROR]</> {$clientDomain->domain}: {$e->getMessage()}");

                Log::error('Domain transfer sync error', [
                    'domain_id' => $clientDomain->id,
                    'domain' => $clientDomain->domain,
                    'error' => $e->getMessage(),
                ]);
            }
        }

        $this->newLine();
        $this->table(
            ['Status', 'Count'],
            [
                ['Completed', $stats['completed']],
                ['Still Pending', $stats['still_pending']],
                ['Failed', $stats['failed']],
                ['Skipped', $stats['skipped']],
            ]
        );

        $this->info('Domain transfer sync completed.');

        return Command::SUCCESS;
    }

    /**
     * Sync a single domain transfer status with registrar
     */
    protected function syncTransfer(ClientDomain $clientDomain): string
    {
        // The transfer was initiated via a specific module (register-time or
        // admin-switched); polling must use that same module, not the TLD
        // default. getEffectiveModuleName() prefers $clientDomain->module.
        $registrarName = $clientDomain->getEffectiveModuleName();
        if (! $registrarName) {
            Log::warning('Skipping transfer sync - no registrar configured', [
                'domain_id' => $clientDomain->id,
                'domain' => $clientDomain->domain,
            ]);

            return 'skipped';
        }

        if (! $this->registrarManager->has($registrarName)) {
            Log::warning('Skipping transfer sync - registrar module not loaded', [
                'domain_id' => $clientDomain->id,
                'domain' => $clientDomain->domain,
                'registrar' => $registrarName,
            ]);

            return 'skipped';
        }

        $registrar = $this->registrarManager->get($registrarName);

        $result = $registrar->syncDomainTransfer(
            \App\Core\Domain\DomainModuleParamsBuilder::build($clientDomain)
        );

        $status = $result['status'] ?? null;
        $data = $result['data'] ?? $result;
        $transferStatus = $data['transfer_status'] ?? $data['status'] ?? null;

        // Transfer completed
        if ($status === 'success' && in_array($transferStatus, ['completed', 'active'])) {
            $updateData = [
                'status' => 'active',
                'last_sync_at' => now(),
                'sync_error' => null,
            ];

            // Extract expire date if available
            $expireDate = $this->extractExpireDate($result);
            if ($expireDate) {
                $updateData['expire_date'] = $expireDate;
            }

            $clientDomain->update($updateData);

            // Send transfer completed email
            $this->sendTransferCompletedEmail($clientDomain);

            Log::info('Domain transfer completed', [
                'domain_id' => $clientDomain->id,
                'domain' => $clientDomain->domain,
            ]);

            return 'completed';
        }

        // Transfer failed
        if ($status === 'failed' || $transferStatus === 'failed' || $transferStatus === 'rejected') {
            $errorMessage = $data['message'] ?? $data['error'] ?? 'Transfer failed at registrar';

            $clientDomain->update([
                'status' => 'failed',
                'provisioning_status' => 'failed',
                'provisioning_error' => $errorMessage,
                'last_sync_at' => now(),
                'sync_error' => $errorMessage,
            ]);

            // Send transfer failed email
            $this->sendTransferFailedEmail($clientDomain, $errorMessage);

            Log::warning('Domain transfer failed at registrar', [
                'domain_id' => $clientDomain->id,
                'domain' => $clientDomain->domain,
                'error' => $errorMessage,
            ]);

            return 'failed';
        }

        // Still pending
        $clientDomain->update([
            'last_sync_at' => now(),
            'sync_error' => null,
        ]);

        return 'pending';
    }

    /**
     * Extract expire date from registrar response
     */
    protected function extractExpireDate(array $result): ?string
    {
        $data = $result['data'] ?? $result;

        $possibleKeys = [
            'expires_at', 'expiry_date', 'expire_date',
            'expiration_date', 'expirationdate',
        ];

        foreach ($possibleKeys as $key) {
            if (! empty($data[$key])) {
                try {
                    return \Carbon\Carbon::parse($data[$key])->toDateString();
                } catch (\Exception $e) {
                    // Skip invalid dates
                }
            }
        }

        return null;
    }

    /**
     * Send transfer completed email to client
     */
    protected function sendTransferCompletedEmail(ClientDomain $clientDomain): void
    {
        try {
            SendEmailJob::dispatch(
                'Domain Transfer Completed',
                'domain',
                $clientDomain->id,
                [
                    'FIRSTNAME' => $clientDomain->client->first_name,
                    'LASTNAME' => $clientDomain->client->last_name,
                    'CLIENT_NAME' => $clientDomain->client->first_name . ' ' . $clientDomain->client->last_name,
                    'DOMAIN' => $clientDomain->domain,
                    'EXPIRYDATE' => $clientDomain->expire_date?->format('d.m.Y') ?? 'N/A',
                    'EXPIRY_DATE' => $clientDomain->expire_date?->format('d.m.Y') ?? 'N/A',
                    'REGISTRAR' => $clientDomain->module ?? 'N/A',
                    'DOMAINURL' => route('store.auth.domains.manage', $clientDomain->id),
                ],
                $clientDomain->client->language ?? 'tr',
                $clientDomain->client->email
            );
        } catch (\Exception $e) {
            Log::warning('Failed to send domain transfer completed email', [
                'domain_id' => $clientDomain->id,
                'error' => $e->getMessage(),
            ]);
        }
    }

    /**
     * Send transfer failed email to client
     */
    protected function sendTransferFailedEmail(ClientDomain $clientDomain, string $errorMessage): void
    {
        try {
            SendEmailJob::dispatch(
                'Domain Transfer Failed',
                'domain',
                $clientDomain->id,
                [
                    'FIRSTNAME' => $clientDomain->client->first_name,
                    'LASTNAME' => $clientDomain->client->last_name,
                    'CLIENT_NAME' => $clientDomain->client->first_name . ' ' . $clientDomain->client->last_name,
                    'DOMAIN' => $clientDomain->domain,
                    'ERROR' => $errorMessage,
                    'DOMAINURL' => route('store.auth.domains.manage', $clientDomain->id),
                ],
                $clientDomain->client->language ?? 'tr',
                $clientDomain->client->email
            );
        } catch (\Exception $e) {
            Log::warning('Failed to send domain transfer failed email', [
                'domain_id' => $clientDomain->id,
                'error' => $e->getMessage(),
            ]);
        }
    }
}
