<?php

namespace App\Console\Commands;

use App\Models\BillService;
use App\Models\BillVariation;
use App\Modules\ProviderIntegration\Interfaces\ProviderInterface;
use Illuminate\Console\Command;

class SyncVTPassServices extends Command
{
    protected $signature = 'vtpass:sync-services {--dry-run : Preview changes without saving}';

    protected $description = 'Fetch services from VTPass API using the 3-step flow (categories → services → variations) and sync to local database';

    private array $categoryMap = [
        'airtime' => 'airtime',
        'data' => 'data',
        'tv-subscription' => 'cable',
        'electricity-bill' => 'electricity',
        'education' => 'exam_pin',
        'other-services' => 'other',
        'insurance' => 'other',
    ];

    public function handle(ProviderInterface $provider): int
    {
        $dryRun = $this->option('dry-run');

        // Step 1: Get service categories
        $this->info('Step 1: Fetching service categories from VTPass...');
        try {
            $catResponse = $provider->getServiceCategories();
        } catch (\Exception $e) {
            $this->error('Failed to fetch categories: ' . $e->getMessage());
            return Command::FAILURE;
        }

        $categories = $catResponse['content'] ?? [];

        if (empty($categories)) {
            $this->warn('No categories returned from VTPass.');
            return Command::SUCCESS;
        }

        $this->info('Found ' . count($categories) . ' categories:');
        foreach ($categories as $cat) {
            $mapped = $this->categoryMap[$cat['identifier']] ?? 'other';
            $this->line("  <info>{$cat['name']}</info> ({$cat['identifier']} → {$mapped})");
        }
        $this->newLine();

        $totalServices = 0;
        $totalVariations = 0;
        $servicesCreated = 0;
        $servicesUpdated = 0;
        $variationsCreated = 0;
        $variationsUpdated = 0;

        // Step 2: For each category, get services
        foreach ($categories as $cat) {
            $identifier = $cat['identifier'];
            $localCategory = $this->categoryMap[$identifier] ?? 'other';

            // Skip categories we don't support
            if ($localCategory === 'other' && !in_array($identifier, ['other-services', 'insurance'])) {
                $this->line("  Skipping unknown category: {$identifier}");
                continue;
            }

            $this->info("Step 2: Fetching services for <info>{$cat['name']}</info>...");

            try {
                $svcResponse = $provider->getServices($identifier);
            } catch (\Exception $e) {
                $this->warn("  Failed to fetch services for {$identifier}: " . $e->getMessage());
                continue;
            }

            $services = $svcResponse['content'] ?? [];

            if (empty($services)) {
                $this->line("  No services found for {$identifier}.");
                continue;
            }

            $this->line("  Found " . count($services) . " services.");

            foreach ($services as $service) {
                $serviceID = $service['serviceID'] ?? null;
                $name = $service['name'] ?? $serviceID;

                if (!$serviceID) {
                    continue;
                }

                $minAmount = $this->parseAmount($service['minimium_amount'] ?? 0);
                $maxAmount = $this->parseAmount($service['maximum_amount'] ?? 0);
                $convenienceFee = $this->parseFee($service['convinience_fee'] ?? '0');
                $image = $service['image'] ?? null;

                if ($dryRun) {
                    $existing = BillService::where('code', $serviceID)->first();
                    $this->line("    <info>{$name}</info> ({$serviceID})" . ($existing ? ' [UPDATE]' : ' [NEW]'));
                    $existing ? $servicesUpdated++ : $servicesCreated++;
                } else {
                    $billService = BillService::updateOrCreate(
                        ['code' => $serviceID],
                        [
                            'name' => $name,
                            'slug' => $this->slugify($serviceID),
                            'category' => $localCategory,
                            'icon' => $this->fixImageUrl($image),
                            'is_active' => true,
                            'min_amount' => $minAmount,
                            'max_amount' => $maxAmount,
                            'service_charge' => $convenienceFee,
                            'metadata' => [
                                'vtpass_service_type' => $service['product_type'] ?? null,
                                'convenience_fee_raw' => $service['convinience_fee'] ?? null,
                                'original_name' => $name,
                            ],
                        ]
                    );

                    if ($billService->wasRecentlyCreated) {
                        $servicesCreated++;
                    } else {
                        $servicesUpdated++;
                    }

                    // Step 3: Get variations for this service
                    $varResult = $this->syncVariations($provider, $billService, $dryRun);
                    $variationsCreated += $varResult['created'];
                    $variationsUpdated += $varResult['updated'];
                    $totalVariations += $varResult['created'] + $varResult['updated'];
                }

                $totalServices++;
            }

            $this->newLine();
        }

        // Summary
        $this->newLine();
        if ($dryRun) {
            $this->info('DRY RUN SUMMARY:');
            $this->line("  Services: {$servicesCreated} to create, {$servicesUpdated} to update");
            $this->line("  Variations: (not counted in dry-run)");
        } else {
            $this->info('SYNC COMPLETE:');
            $this->line("  Services: {$servicesCreated} created, {$servicesUpdated} updated");
            $this->line("  Variations: {$variationsCreated} created, {$variationsUpdated} updated");
        }

        return Command::SUCCESS;
    }

    private function syncVariations(ProviderInterface $provider, BillService $billService, bool $dryRun): array
    {
        $created = 0;
        $updated = 0;

        try {
            $response = $provider->getVariations($billService->code);
        } catch (\Exception $e) {
            $this->warn("    Failed to fetch variations for {$billService->code}: " . $e->getMessage());
            return ['created' => 0, 'updated' => 0];
        }

        $content = $response['content'] ?? $response['service_variations'] ?? [];
        $variations = $content['variations'] ?? [];

        foreach ($variations as $variation) {
            $variationCode = $variation['variation_code'] ?? null;
            $name = $variation['name'] ?? $variationCode;
            $amount = $this->parseAmount($variation['variation_amount'] ?? 0);
            $fixedPrice = ($variation['fixedPrice'] ?? '') === 'Yes';

            if (!$variationCode) {
                continue;
            }

            if ($dryRun) {
                $existing = BillVariation::where('code', $variationCode)->first();
                $this->line("      {$name} ({$variationCode}) ₦{$amount}" . ($existing ? ' [UPDATE]' : ' [NEW]'));
                $existing ? $updated++ : $created++;
            } else {
                $result = BillVariation::updateOrCreate(
                    ['code' => $variationCode],
                    [
                        'bill_service_id' => $billService->id,
                        'name' => $name,
                        'amount' => $amount,
                        'is_active' => true,
                        'metadata' => [
                            'fixed_price' => $fixedPrice,
                            'original_name' => $name,
                        ],
                    ]
                );

                if ($result->wasRecentlyCreated) {
                    $created++;
                } else {
                    $updated++;
                }
            }
        }

        return ['created' => $created, 'updated' => $updated];
    }

    private function parseAmount(mixed $value): float
    {
        if (is_numeric($value)) {
            return (float) $value;
        }

        $cleaned = preg_replace('/[^0-9.]/', '', (string) $value);
        return $cleaned ? (float) $cleaned : 0.0;
    }

    private function parseFee(mixed $value): float
    {
        $str = (string) $value;

        if (preg_match('/(\d+)/', $str, $matches)) {
            return (float) $matches[1];
        }

        return 0.0;
    }

    private function slugify(string $value): string
    {
        return strtolower(trim(preg_replace('/[^A-Za-z0-9-]+/', '-', $value), '-'));
    }

    private function fixImageUrl(?string $url): ?string
    {
        if (!$url) {
            return null;
        }

        return str_replace('sandbox.vtpass.com', 'vtpass.com', $url);
    }
}
