<?php

namespace App\Console\Commands;

use App\Models\App;
use App\Models\Category;
use Carbon\Carbon;
use Exception;
use Illuminate\Console\Command;
use Illuminate\Support\Facades\Http;
use Illuminate\Support\Facades\Log;
use Illuminate\Support\Str;
use Illuminate\Http\Client\PendingRequest;
use Illuminate\Database\Eloquent\Builder;

class AppImportNew extends Command
{
    /**
     * The name and signature of the console command.
     *
     * @var string
     */
    protected $signature = 'app:import-new {--source= : Import from specific source} {--force : Force update even if version is same}';

    /**
     * The console command description.
     *
     * @var string
     */
    protected $description = 'Import new apps from multiple sources and update existing ones';

    /**
     * Available import sources configuration.
     *
     * @var array<string, array<string, mixed>>
     */
    protected $sources = [
        'source_a' => [
            'name' => 'Source A',
            'base_url' => 'https://api.source-a.com/v1',
            'endpoints' => [
                'latest' => '/apps/latest',
                'categories' => '/categories',
                'app_details' => '/apps/{id}',
            ],
            'headers' => [
                'Accept' => 'application/json',
                'User-Agent' => 'SuperAPKHub/1.0',
            ],
        ],
        'source_b' => [
            'name' => 'Source B',
            'base_url' => 'https://source-b.com/api',
            'endpoints' => [
                'latest' => '/recent',
                'categories' => '/categories',
                'app_details' => '/app/{id}',
            ],
            'headers' => [
                'Accept' => 'application/json',
                'User-Agent' => 'SuperAPKHub/1.0',
            ],
        ],
    ];

    /**
     * Execute the console command.
     *
     * @return int
     */
    public function handle(): int
    {
        $sourceKey = $this->option('source');
        $force = (bool) $this->option('force');

        $this->info('Starting app import process...');
        $this->info('Source: ' . ($sourceKey ?: 'All sources'));
        $this->info('Force update: ' . ($force ? 'Yes' : 'No'));

        try {
            if ($sourceKey) {
                if (!isset($this->sources[$sourceKey])) {
                    $this->error("Source '{$sourceKey}' not found.");
                    $this->info('Available sources: ' . implode(', ', $this->getAvailableSources()));
                    return 1;
                }
                // تم تمرير مفتاح المصدر فقط، وسنستخدم المصفوفة الداخلية
                $this->importFromSource($sourceKey, $force);
            } else {
                foreach ($this->sources as $key => $config) {
                    $this->importFromSource($key, $force);
                }
            }

            $this->info('Import process completed successfully!');
            return 0;
        } catch (Exception $e) {
            $this->error('Import process failed: ' . $e->getMessage());
            Log::error('App import failed', [
                'error' => $e->getMessage(),
                'source' => $sourceKey,
                'trace' => $e->getTraceAsString(),
            ]);
            return 1;
        }
    }

    /**
     * Import apps from a specific source.
     *
     * @param string $sourceKey
     * @param bool $force
     * @return void
     * @throws Exception
     */
    protected function importFromSource(string $sourceKey, bool $force): void
    {
        $sourceConfig = $this->sources[$sourceKey];
        $this->info("Importing from {$sourceConfig['name']}...");

        // استخدام Http Client مع Base URL و Headers لتبسيط الطلبات
        $client = Http::baseUrl($sourceConfig['base_url'])
            ->withHeaders($sourceConfig['headers'])
            ->timeout(30);

        try {
            // Import categories first
            $this->importCategories($client, $sourceConfig);

            // Import apps
            $this->importApps($client, $sourceConfig, $force);

            $this->info("Successfully imported from {$sourceConfig['name']}");
        } catch (Exception $e) {
            $this->error("Failed to import from {$sourceConfig['name']}: " . $e->getMessage());
            // إعادة رمي الاستثناء ليتم التقاطه في دالة handle
            throw $e;
        }
    }

    /**
     * Import categories from source.
     *
     * @param PendingRequest $client
     * @param array $sourceConfig
     * @return void
     * @throws Exception
     */
    protected function importCategories(PendingRequest $client, array $sourceConfig): void
    {
        $this->line('Importing categories...');

        $response = $client->get($sourceConfig['endpoints']['categories']);

        if (!$response->successful()) {
            throw new Exception("Failed to fetch categories: " . $response->status());
        }

        $categories = $response->json();
        $importedCount = 0;

        foreach ($categories as $categoryData) {
            $slug = Str::slug($categoryData['name']);

            $category = Category::updateOrCreate(
                ['slug' => $slug],
                [
                    'name' => $categoryData['name'],
                    'description' => $categoryData['description'] ?? null,
                    'icon' => $categoryData['icon'] ?? null,
                    'color' => $categoryData['color'] ?? null,
                    'status' => 'active',
                ]
            );

            if ($category->wasRecentlyCreated) {
                $importedCount++;
            }
        }

        $this->line("Imported {$importedCount} new categories");
    }

    /**
     * Import apps from source.
     *
     * @param PendingRequest $client
     * @param array $sourceConfig
     * @param bool $force
     * @return void
     * @throws Exception
     */
    protected function importApps(PendingRequest $client, array $sourceConfig, bool $force): void
    {
        $this->line('Importing apps...');

        $response = $client->get($sourceConfig['endpoints']['latest']);

        if (!$response->successful()) {
            throw new Exception("Failed to fetch apps: " . $response->status());
        }

        $apps = $response->json();
        $importedCount = 0;
        $updatedCount = 0;
        $skippedCount = 0;

        $progressBar = $this->output->createProgressBar(count($apps));
        $progressBar->start();

        foreach ($apps as $appData) {
            try {
                // Get detailed app information
                $detailsResponse = $client->get(
                    str_replace('{id}', $appData['id'], $sourceConfig['endpoints']['app_details'])
                );

                if (!$detailsResponse->successful()) {
                    $this->warn("Failed to fetch details for app {$appData['id']}");
                    $progressBar->advance();
                    continue;
                }

                $detailedData = $detailsResponse->json();

                // Find or create the app
                $existingApp = App::where('package_name', $detailedData['package_name'])->first();

                $shouldUpdate = false;

                if ($existingApp) {
                    if ($force || $this->isNewerVersion($detailedData['version_code'], $existingApp->version_code ?? 0)) {
                        $shouldUpdate = true;
                    } else {
                        $skippedCount++;
                    }
                } else {
                    $shouldUpdate = true;
                }

                if ($shouldUpdate) {
                    // البحث عن الفئة بناءً على الـ slug
                    $categorySlug = Str::slug($detailedData['category'] ?? 'uncategorized');
                    $category = Category::where('slug', $categorySlug)->first();

                    $appData = $this->normalizeAppData($detailedData, $category);

                    $app = App::updateOrCreate(
                        ['package_name' => $appData['package_name']],
                        $appData
                    );

                    // Import versions if available
                    if (isset($detailedData['versions'])) {
                        $this->importVersions($app, $detailedData['versions']);
                    }

                    if ($app->wasRecentlyCreated) {
                        $importedCount++;
                    } elseif ($existingApp) { // تم التحديث
                        $updatedCount++;
                        Log::info('App updated', [
                            'package_name' => $app->package_name,
                            'old_version' => $existingApp->version_code ?? 'N/A',
                            'new_version' => $app->version_code,
                            'source' => $sourceConfig['name'],
                        ]);
                    }
                }
            } catch (Exception $e) {
                $this->warn("Error processing app: " . $e->getMessage());
                Log::error('Error processing app', [
                    'app_id' => $appData['id'] ?? 'Unknown',
                    'error' => $e->getMessage(),
                    'source' => $sourceConfig['name'],
                ]);
            }

            $progressBar->advance();
        }

        $progressBar->finish();
        $this->newLine();

        $this->line("Imported {$importedCount} new apps");
        $this->line("Updated {$updatedCount} existing apps");
        $this->line("Skipped {$skippedCount} apps (no updates needed)");
    }

    /**
     * Import versions for an app.
     *
     * @param App $app
     * @param array $versions
     * @return void
     */
    protected function importVersions(App $app, array $versions): void
    {
        foreach ($versions as $versionData) {
            $app->versions()->updateOrCreate(
                ['version_code' => $versionData['code']],
                [
                    'version_name' => $versionData['name'],
                    'release_date' => isset($versionData['release_date']) ? Carbon::parse($versionData['release_date']) : null,
                    'changelog' => $versionData['changelog'] ?? null,
                    'download_url' => $versionData['download_url'] ?? null,
                    'size' => $versionData['size'] ?? null,
                    'min_os_version' => $versionData['min_os'] ?? null,
                    'max_os_version' => $versionData['max_os'] ?? null,
                    'is_beta' => $versionData['beta'] ?? false,
                    'status' => 'active',
                ]
            );
        }
    }

    /**
     * Normalize app data from different sources.
     *
     * @param array $data
     * @param Category|null $category
     * @return array<string, mixed>
     */
    protected function normalizeAppData(array $data, ?Category $category): array
    {
        return [
            'package_name' => $data['package_name'],
            'slug' => Str::slug($data['name']),
            'name' => $data['name'],
            'description' => $this->cleanDescription($data['description'] ?? ''),
            'icon_url' => $data['icon'] ?? null,
            'latest_version' => $data['version'] ?? null,
            'version_code' => $data['version_code'] ?? 0,
            'rating' => $data['rating'] ?? 0,
            'downloads_count' => $data['downloads'] ?? 0,
            'os_requirement' => $data['os_requirement'] ?? null,
            'category_id' => $category?->id,
            'developer' => $data['developer'] ?? null,
            'size' => $data['size'] ?? null,
            'mod_info' => $data['mod_info'] ?? null,
            'screenshots' => $data['screenshots'] ?? [],
            'download_url' => $data['download_url'] ?? null,
            'status' => 'active',
            'featured' => $data['featured'] ?? false,
            'updated_at' => now(),
        ];
    }

    /**
     * Check if the new version is newer than the existing one.
     *
     * @param int|string $newVersion
     * @param int|string $oldVersion
     * @return bool
     */
    protected function isNewerVersion(int|string $newVersion, int|string $oldVersion): bool
    {
        return intval($newVersion) > intval($oldVersion);
    }

    /**
     * Clean and normalize description text.
     *
     * @param string $description
     * @return string
     */
    protected function cleanDescription(string $description): string
    {
        $description = strip_tags($description);
        $description = preg_replace('/\s+/', ' ', $description);
        return trim($description);
    }

    /**
     * Get available sources from configuration.
     *
     * @return array<int, string>
     */
    protected function getAvailableSources(): array
    {
        return array_keys($this->sources);
    }
}