<?php

namespace App\Console\Commands;

use Illuminate\Console\Command;
use Illuminate\Support\Facades\DB;

class ValidateTagTranslations extends Command
{
    protected $signature = 'tags:validate-translations
                            {--locale= : Check specific locale only}
                            {--show-missing : Show contexts missing translations in specific locales}
                            {--show-duplicates : Show duplicate tag names within same locale}
                            {--show-contexts : Show context distribution}';

    // Example to show missing context (tags that are not translated in all languages)
    // php artisan tags:validate-translations --locale=nl --show-missing

    // Example to show and remove duplicate tags
    // Note that only if you include the locale flag you will be asked to remove any duplicates
    // php artisan tags:validate-translations --locale=de --show-duplicates

    protected $description = 'Validate tag translations across all supported locales';

    protected array $supportedLocales = ['en', 'nl', 'fr', 'es', 'de'];

    public function handle()
    {
        $specificLocale = $this->option('locale');
        $showMissing = $this->option('show-missing');
        $showDuplicates = $this->option('show-duplicates');
        $showContexts = $this->option('show-contexts');

        $locales = $specificLocale ? [$specificLocale] : $this->supportedLocales;

        $this->info('Validating tag structure and translations...');

        // Get total tags and contexts
        $totalTags = DB::table('taggable_tags')->count();
        $totalContexts = DB::table('taggable_contexts')->count();

        $this->info("Total tags: {$totalTags}");
        $this->info("Total contexts: {$totalContexts}");

        // Show tag distribution by locale
        $results = [];

        foreach ($locales as $locale) {
            $tagsInLocale = DB::table('taggable_tags')
                ->join('taggable_locales', 'taggable_tags.tag_id', '=', 'taggable_locales.taggable_tag_id')
                ->where('taggable_locales.locale', $locale)
                ->count();

            // Count contexts that have tags in this locale
            $contextsWithLocale = DB::table('taggable_contexts')
                ->join('taggable_locale_context', 'taggable_contexts.id', '=', 'taggable_locale_context.context_id')
                ->join('taggable_locales', 'taggable_locale_context.tag_id', '=', 'taggable_locales.taggable_tag_id')
                ->where('taggable_locales.locale', $locale)
                ->distinct('taggable_contexts.id')
                ->count();

            $missingContexts = $totalContexts - $contextsWithLocale;
            $percentage = $totalContexts > 0 ? round(($contextsWithLocale / $totalContexts) * 100, 1) : 0;

            $results[] = [
                'locale' => $locale,
                'tags' => $tagsInLocale,
                'contexts_covered' => $contextsWithLocale,
                'contexts_missing' => $missingContexts,
                'coverage' => $percentage . '%'
            ];
        }

        $this->newLine();
        $this->table(['Locale', 'Tags', 'Contexts Covered', 'Missing Contexts', 'Coverage'], $results);

        if ($showMissing && $specificLocale) {
            $this->showMissingContextsForLocale($specificLocale);
        }

        if ($showDuplicates && $specificLocale) {
            $this->showDuplicateTagsInLocale($specificLocale);
        }

        if ($showContexts) {
            $this->showContextDistribution();
        }

        // Check for orphaned data
        $this->checkOrphanedData();

        $this->newLine();
        $this->info('Validation complete!');

        return 0;
    }

    /**
     * Show contexts that are missing tags in a specific locale
     */
    protected function showMissingContextsForLocale(string $locale): void
    {
        $this->newLine();
        $this->info("Analyzing missing contexts for locale: {$locale}");

        // Get all context IDs that DO have tags in the specified locale
        $contextsWithLocale = DB::table('taggable_locale_context as tlc')
            ->join('taggable_locales as tl', 'tlc.tag_id', '=', 'tl.taggable_tag_id')
            ->where('tl.locale', $locale)
            ->distinct()
            ->pluck('tlc.context_id');

        // Get contexts that DON'T have tags in the specified locale
        $missingContexts = DB::table('taggable_contexts as tc')
            ->whereNotIn('tc.id', $contextsWithLocale)
            ->join('categories as c', 'tc.category_id', '=', 'c.id')
            ->join('category_translations as ct', function ($join) {
                $join->on('c.id', '=', 'ct.category_id')
                    ->where('ct.locale', '=', 'en');
            })
            ->select(
                'tc.id as context_id',
                'tc.category_id',
                'ct.name as category_name',
                'ct.slug as category_slug'
            )
            ->distinct()
            ->get();

        if ($missingContexts->isEmpty()) {
            $this->info("✓ All contexts have tags in {$locale}!");
            return;
        }

        $this->warn("Found " . $missingContexts->count() . " contexts missing {$locale} tags:");
        $this->newLine();

        foreach ($missingContexts as $context) {
            $this->line("📂 <fg=yellow>Context {$context->context_id}</fg=yellow>: {$context->category_name}");

            // Show what tags exist in other languages for this context
            $existingTags = DB::table('taggable_locale_context as tlc')
                ->join('taggable_tags as tt', 'tlc.tag_id', '=', 'tt.tag_id')
                ->join('taggable_locales as tl', 'tt.tag_id', '=', 'tl.taggable_tag_id')
                ->where('tlc.context_id', $context->context_id)
                ->select('tt.tag_id', 'tt.name', 'tl.locale')
                ->orderBy('tl.locale')
                ->get()
                ->groupBy('locale');

            if ($existingTags->isNotEmpty()) {
                $this->line("  <fg=green>Existing tags in other languages:</fg=green>");
                foreach ($existingTags as $existingLocale => $tags) {
                    $tagNames = $tags->pluck('name')->take(3)->implode(', ');
                    $moreCount = $tags->count() > 3 ? ' (+' . ($tags->count() - 3) . ' more)' : '';
                    $this->line("   • {$existingLocale}: {$tagNames}{$moreCount}");
                }
            }

            $this->line("  <fg=cyan>💡 Action needed:</fg=cyan> Create {$locale} tags for this context");
            $this->newLine();
        }

        // Provide actionable summary
        $this->info("🔧 How to fix missing contexts:");
        $this->line("1. Create {$locale} tags that represent the same skills/concepts");
        $this->line("2. Link them to the appropriate context using the JSON import:");
        $this->newLine();

        // Generate example JSON structure
        $this->line("<fg=green>Example JSON structure to create missing {$locale} tags:</fg=green>");
        $this->line('{');
        $this->line('  "tags": [');

        $exampleContext = $missingContexts->first();
        if ($exampleContext) {
            // Get an example tag from another language for this context
            $exampleTag = DB::table('taggable_locale_context as tlc')
                ->join('taggable_tags as tt', 'tlc.tag_id', '=', 'tt.tag_id')
                ->join('taggable_locales as tl', 'tt.tag_id', '=', 'tl.taggable_tag_id')
                ->where('tlc.context_id', $exampleContext->context_id)
                ->where('tl.locale', 'en')
                ->select('tt.name')
                ->first();

            $exampleName = $exampleTag ? $exampleTag->name : 'Example Skill Name';
            $translatedName = $this->getExampleTranslation($exampleName, $locale);

            $this->line('    {');
            $this->line('      "translations": {');
            $this->line("        \"{$locale}\": \"{$translatedName}\"");
            $this->line('      },');
            $this->line('      "category": {');
            $this->line("        \"id\": {$exampleContext->context_id},");
            $this->line("        \"name\": \"{$exampleContext->category_name}\"");
            $this->line('      }');
            $this->line('    }');
        }

        $this->line('  ]');
        $this->line('}');
        $this->newLine();
        $this->line("3. Import using: <fg=cyan>php artisan tags:import-json your-{$locale}-tags.json</fg=cyan>");
    }

    /**
     * Get example translation for demonstration
     */
    protected function getExampleTranslation(string $englishName, string $locale): string
    {
        $translations = [
            'nl' => [
                'Math Tutoring' => 'Wiskunde Bijles',
                'Science Help' => 'Wetenschap Hulp',
                'Language Exchange' => 'Taaluitwisseling',
                'Programming' => 'Programmeren',
                'Cooking' => 'Koken',
                'Photography' => 'Fotografie',
            ],
            'fr' => [
                'Math Tutoring' => 'Cours de Mathématiques',
                'Science Help' => 'Aide Scientifique',
                'Language Exchange' => 'Échange Linguistique',
                'Programming' => 'Programmation',
                'Cooking' => 'Cuisine',
                'Photography' => 'Photographie',
            ],
            'es' => [
                'Math Tutoring' => 'Clases de Matemáticas',
                'Science Help' => 'Ayuda Científica',
                'Language Exchange' => 'Intercambio de Idiomas',
                'Programming' => 'Programación',
                'Cooking' => 'Cocina',
                'Photography' => 'Fotografía',
            ],
            'de' => [
                'Math Tutoring' => 'Mathe Nachhilfe',
                'Science Help' => 'Wissenschaft Hilfe',
                'Language Exchange' => 'Sprachaustausch',
                'Programming' => 'Programmierung',
                'Cooking' => 'Kochen',
                'Photography' => 'Fotografie',
            ],
        ];

        return $translations[$locale][$englishName] ?? $englishName . " ({$locale})";
    }

    /**
     * Show duplicate tag names within the same locale
     */
    protected function showDuplicateTagsInLocale(string $locale): void
    {
        $duplicates = DB::table('taggable_tags')
            ->join('taggable_locales', 'taggable_tags.tag_id', '=', 'taggable_locales.taggable_tag_id')
            ->where('taggable_locales.locale', $locale)
            ->select('taggable_tags.name', DB::raw('COUNT(*) as count'), DB::raw('GROUP_CONCAT(taggable_tags.tag_id) as tag_ids'))
            ->groupBy('taggable_tags.name')
            ->having('count', '>', 1)
            ->get();

        if ($duplicates->isEmpty()) {
            $this->newLine();
            $this->info("✓ No duplicate tag names found in {$locale}!");
            return;
        }

        $this->newLine();
        $this->warn("Found duplicate tag names in {$locale}:");

        foreach ($duplicates as $duplicate) {
            $tagIds = explode(',', $duplicate->tag_ids);
            $this->line("  <fg=yellow>'{$duplicate->name}'</fg=yellow> appears {$duplicate->count} times (tag IDs: {$duplicate->tag_ids})");

            // Show details for each duplicate tag
            foreach ($tagIds as $tagId) {
                $contexts = DB::table('taggable_locale_context as tlc')
                    ->join('taggable_contexts as tc', 'tlc.context_id', '=', 'tc.id')
                    ->join('categories as c', 'tc.category_id', '=', 'c.id')
                    ->join('category_translations as ct', function ($join) {
                        $join->on('c.id', '=', 'ct.category_id')
                            ->where('ct.locale', '=', 'en');
                    })
                    ->where('tlc.tag_id', $tagId)
                    ->select('tc.id as context_id', 'ct.name as category_name')
                    ->get();

                $contextInfo = $contexts->isEmpty() ? 'No contexts' :
                    $contexts->map(fn($c) => "Context {$c->context_id} ({$c->category_name})")->implode(', ');

                $this->line("    Tag ID {$tagId}: {$contextInfo}");
            }
        }

        // Prompt to remove duplicates
        $this->newLine();
        if ($this->confirm("Do you want to remove duplicate tags for locale '{$locale}'? This will keep the first occurrence and remove others.")) {
            $this->removeDuplicateTagsForLocale($locale, $duplicates);
        }
    }

    /**
     * Remove duplicate tags for a specific locale
     */
    protected function removeDuplicateTagsForLocale(string $locale, $duplicates): void
    {
        $this->newLine();
        $this->info("Removing duplicate tags for locale: {$locale}");

        $totalRemoved = 0;

        DB::transaction(function () use ($locale, $duplicates, &$totalRemoved) {
            foreach ($duplicates as $duplicate) {
                $tagIds = explode(',', $duplicate->tag_ids);

                // Keep the first tag, remove the rest
                $keepTagId = array_shift($tagIds);
                $removeTagIds = $tagIds;

                $this->line("  Processing '{$duplicate->name}':");
                $this->line("    Keeping tag ID: {$keepTagId}");
                $this->line("    Removing tag IDs: " . implode(', ', $removeTagIds));

                foreach ($removeTagIds as $removeTagId) {
                    // First, transfer any context associations to the kept tag
                    $contexts = DB::table('taggable_locale_context')
                        ->where('tag_id', $removeTagId)
                        ->pluck('context_id');

                    foreach ($contexts as $contextId) {
                        // Check if the kept tag already has this context association
                        $existingAssociation = DB::table('taggable_locale_context')
                            ->where('tag_id', $keepTagId)
                            ->where('context_id', $contextId)
                            ->exists();

                        if (!$existingAssociation) {
                            // Transfer the context association to the kept tag
                            try {
                                DB::table('taggable_locale_context')
                                    ->where('tag_id', $removeTagId)
                                    ->where('context_id', $contextId)
                                    ->update(['tag_id' => $keepTagId]);

                                $this->line("      Transferred context {$contextId} to kept tag");
                            } catch (\Illuminate\Database\UniqueConstraintViolationException $e) {
                                // If update fails due to unique constraint, just delete the duplicate
                                DB::table('taggable_locale_context')
                                    ->where('tag_id', $removeTagId)
                                    ->where('context_id', $contextId)
                                    ->delete();

                                $this->line("      Removed duplicate context association {$contextId} (kept tag already has this context)");
                            }
                        } else {
                            // Remove the duplicate context association
                            DB::table('taggable_locale_context')
                                ->where('tag_id', $removeTagId)
                                ->where('context_id', $contextId)
                                ->delete();

                            $this->line("      Removed duplicate context association {$contextId} (already exists on kept tag)");
                        }
                    }

                    // Remove the locale record for this tag
                    DB::table('taggable_locales')
                        ->where('taggable_tag_id', $removeTagId)
                        ->where('locale', $locale)
                        ->delete();

                    // Check if this tag has any other locale records
                    $hasOtherLocales = DB::table('taggable_locales')
                        ->where('taggable_tag_id', $removeTagId)
                        ->exists();

                    // If no other locales exist, remove the tag entirely
                    if (!$hasOtherLocales) {
                        DB::table('taggable_tags')
                            ->where('tag_id', $removeTagId)
                            ->delete();

                        $this->line("      Removed tag {$removeTagId} entirely (no other locales)");
                    } else {
                        $this->line("      Removed {$locale} locale for tag {$removeTagId} (other locales exist)");
                    }

                    $totalRemoved++;
                }
            }
        });

        $this->newLine();
        $this->info("✓ Successfully removed {$totalRemoved} duplicate tags for locale '{$locale}'");
        $this->info("✓ Context associations have been preserved on the remaining tags");

        // Run a quick verification
        $this->newLine();
        $this->info("Verifying removal...");
        $remainingDuplicates = DB::table('taggable_tags')
            ->join('taggable_locales', 'taggable_tags.tag_id', '=', 'taggable_locales.taggable_tag_id')
            ->where('taggable_locales.locale', $locale)
            ->select('taggable_tags.name', DB::raw('COUNT(*) as count'))
            ->groupBy('taggable_tags.name')
            ->having('count', '>', 1)
            ->count();

        if ($remainingDuplicates === 0) {
            $this->info("✓ No duplicate tags remain in locale '{$locale}'");
        } else {
            $this->warn("⚠ {$remainingDuplicates} duplicate tag names still exist. You may need to run this again.");
        }
    }

    /**
     * Show distribution of tags across contexts
     */
    protected function showContextDistribution(): void
    {
        $distribution = DB::table('taggable_contexts')
            ->leftJoin('taggable_locale_context', 'taggable_contexts.id', '=', 'taggable_locale_context.context_id')
            ->join('categories', 'taggable_contexts.category_id', '=', 'categories.id')
            ->join('category_translations', function ($join) {
                $join->on('categories.id', '=', 'category_translations.category_id')
                    ->where('category_translations.locale', '=', 'en');
            })
            ->select(
                'taggable_contexts.id as context_id',
                'category_translations.name as category_name',
                DB::raw('COUNT(taggable_locale_context.tag_id) as tag_count')
            )
            ->groupBy('taggable_contexts.id', 'category_translations.name')
            ->orderBy('tag_count', 'desc')
            ->limit(10)
            ->get();

        $this->newLine();
        $this->info('Top 10 contexts by tag count:');
        $this->table(
            ['Context ID', 'Category', 'Tag Count'],
            $distribution->map(fn($item) => [
                $item->context_id,
                $item->category_name,
                $item->tag_count
            ])->toArray()
        );
    }

    /**
     * Check for orphaned data
     */
    protected function checkOrphanedData(): void
    {
        // Orphaned locale records
        $orphanedLocales = DB::table('taggable_locales')
            ->leftJoin('taggable_tags', 'taggable_locales.taggable_tag_id', '=', 'taggable_tags.tag_id')
            ->whereNull('taggable_tags.tag_id')
            ->count();

        // Orphaned context links
        $orphanedContextLinks = DB::table('taggable_locale_context')
            ->leftJoin('taggable_tags', 'taggable_locale_context.tag_id', '=', 'taggable_tags.tag_id')
            ->whereNull('taggable_tags.tag_id')
            ->count();

        // Tags without locale specification
        $tagsWithoutLocale = DB::table('taggable_tags')
            ->leftJoin('taggable_locales', 'taggable_tags.tag_id', '=', 'taggable_locales.taggable_tag_id')
            ->whereNull('taggable_locales.id')
            ->count();

        // Tags without context
        $tagsWithoutContext = DB::table('taggable_tags')
            ->leftJoin('taggable_locale_context', 'taggable_tags.tag_id', '=', 'taggable_locale_context.tag_id')
            ->whereNull('taggable_locale_context.id')
            ->count();

        $this->newLine();
        $this->info('Data integrity check:');

        if ($orphanedLocales > 0) {
            $this->warn("Orphaned locale records: {$orphanedLocales}");
        }

        if ($orphanedContextLinks > 0) {
            $this->warn("Orphaned context links: {$orphanedContextLinks}");
        }

        if ($tagsWithoutLocale > 0) {
            $this->warn("Tags without locale specification: {$tagsWithoutLocale}");
        }

        if ($tagsWithoutContext > 0) {
            $this->warn("Tags without context: {$tagsWithoutContext}");
        }

        if ($orphanedLocales === 0 && $orphanedContextLinks === 0 && $tagsWithoutLocale === 0 && $tagsWithoutContext === 0) {
            $this->info('✓ No data integrity issues found');
        }
    }
}
