<?php

namespace App\Console\Commands;

use App\Models\MsgraphPendingChange;
use App\Models\MsgraphModelChange;
use App\Models\ContactFolder;
use App\Models\Committee;
use App\Models\WorkGroup;
use App\Models\User;
use App\Models\MicrosoftUser;
use App\Services\MicrosoftGraph\MicrosoftGraphApiClient;
use Illuminate\Console\Command;
use Illuminate\Support\Facades\DB;

class DiagnoseSmartSync extends Command
{
    protected $signature = 'diagnose:smart-sync
                            {--detailed : Show detailed diagnostics}
                            {--fix-issues : Attempt to fix common issues}';

    protected $description = 'Diagnose the smart sync system and identify potential issues';

    public function handle()
    {
        $this->info('🔍 Diagnosing Microsoft Graph Smart Sync System...');
        $this->newLine();

        $issues = [];

        // Check database tables
        $issues = array_merge($issues, $this->checkDatabaseTables());

        // Check pending changes
        $issues = array_merge($issues, $this->checkPendingChanges());

        // Check contact folders structure
        $issues = array_merge($issues, $this->checkContactFolders());

        // Check service availability
        $issues = array_merge($issues, $this->checkServices());

        // Show summary
        $this->showSummary($issues);

        if ($this->option('fix-issues') && !empty($issues)) {
            $this->attemptFixes($issues);
        }

        return empty($issues) ? 0 : 1;
    }

    private function checkDatabaseTables(): array
    {
        $this->info('📊 Checking database tables...');
        $issues = [];

        // Check if tracking tables exist
        try {
            $pendingCount = MsgraphPendingChange::count();
            $modelCount = MsgraphModelChange::count();

            $this->line("   ✅ msgraph_pending_changes: {$pendingCount} records");
            $this->line("   ✅ msgraph_model_changes: {$modelCount} records");
        } catch (\Exception $e) {
            $issues[] = [
                'type' => 'critical',
                'message' => 'Tracking tables not found or inaccessible',
                'details' => $e->getMessage(),
                'fix' => 'Run migrations: php artisan migrate'
            ];
        }

        // Check contact folders table
        try {
            $folderCount = ContactFolder::count();
            $this->line("   ✅ contact_folders: {$folderCount} records");
        } catch (\Exception $e) {
            $issues[] = [
                'type' => 'critical',
                'message' => 'ContactFolder table not accessible',
                'details' => $e->getMessage(),
                'fix' => 'Check contact folders migration'
            ];
        }

        return $issues;
    }

    private function checkPendingChanges(): array
    {
        $this->info('📋 Checking pending changes...');
        $issues = [];

        // Check for very old unprocessed changes
        $oldChanges = MsgraphPendingChange::unprocessed()
            ->where('created_at', '<', now()->subDays(7))
            ->count();

        if ($oldChanges > 0) {
            $issues[] = [
                'type' => 'warning',
                'message' => "Found {$oldChanges} unprocessed changes older than 7 days",
                'details' => 'This might indicate sync is not running regularly',
                'fix' => 'Check cron schedule or run manual sync'
            ];
        }

        // Check for high priority changes
        $highPriorityChanges = MsgraphPendingChange::unprocessed()
            ->where('priority', 'high')
            ->count();

        if ($highPriorityChanges > 0) {
            $this->warn("   ⚠️ {$highPriorityChanges} high priority membership changes pending");
        }

        $modelHighPriority = MsgraphModelChange::unprocessed()
            ->where('priority', 'high')
            ->count();

        if ($modelHighPriority > 0) {
            $this->warn("   ⚠️ {$modelHighPriority} high priority model changes pending");
        }

        // Check for broken references
        $orphanedMembership = DB::table('msgraph_pending_changes as mpc')
            ->leftJoin('users as u', 'mpc.user_id', '=', 'u.id')
            ->whereNull('u.id')
            ->count();

        if ($orphanedMembership > 0) {
            $issues[] = [
                'type' => 'error',
                'message' => "Found {$orphanedMembership} pending changes with missing user references",
                'fix' => 'Clean up orphaned records'
            ];
        }

        $this->line("   📊 Unprocessed membership changes: " . MsgraphPendingChange::unprocessed()->count());
        $this->line("   📊 Unprocessed model changes: " . MsgraphModelChange::unprocessed()->count());

        return $issues;
    }

    private function checkContactFolders(): array
    {
        $this->info('📁 Checking contact folders structure...');
        $issues = [];

        // Check committees with contact folders
        $committeesWithFolders = Committee::whereHas('contactFolders', function($query) {
            $query->whereNotNull('ms_folder_id');
        })->count();

        $totalCommittees = Committee::where('status', 'published')->count();

        $this->line("   📊 Committees with MS folders: {$committeesWithFolders}/{$totalCommittees}");

        // Check workgroups with contact folders
        $workgroupsWithFolders = WorkGroup::whereHas('contactFolders', function($query) {
            $query->whereNotNull('ms_folder_id');
        })->count();

        $totalWorkgroups = WorkGroup::count();

        $this->line("   📊 WorkGroups with MS folders: {$workgroupsWithFolders}/{$totalWorkgroups}");

        // Check for contact folders without ms_folder_id
        $foldersWithoutMsId = ContactFolder::whereNull('ms_folder_id')->count();

        if ($foldersWithoutMsId > 0) {
            $issues[] = [
                'type' => 'warning',
                'message' => "Found {$foldersWithoutMsId} contact folders without Microsoft Graph ID",
                'details' => 'These folders are not synced to Microsoft Graph',
                'fix' => 'Run full sync to create missing folders'
            ];
        }

        return $issues;
    }

    private function checkServices(): array
    {
        $this->info('🔧 Checking services...');
        $issues = [];

        // Check Microsoft Graph availability
        try {
            $available = MicrosoftGraphApiClient::isAvailable();
            if ($available) {
                $this->line("   ✅ Microsoft Graph API: Available");
            } else {
                $issues[] = [
                    'type' => 'critical',
                    'message' => 'Microsoft Graph API is not available',
                    'fix' => 'Check configuration and network connectivity'
                ];
            }
        } catch (\Exception $e) {
            $issues[] = [
                'type' => 'critical',
                'message' => 'Error checking Microsoft Graph availability',
                'details' => $e->getMessage()
            ];
        }

        // Check for service user
        $serviceUser = MicrosoftUser::whereNotNull('ms_id')->first();
        if ($serviceUser) {
            $this->line("   ✅ Service user: {$serviceUser->email}");
        } else {
            $issues[] = [
                'type' => 'error',
                'message' => 'No Microsoft service user found',
                'details' => 'Required for Microsoft Graph operations',
                'fix' => 'Configure Microsoft service user'
            ];
        }

        return $issues;
    }

    private function showSummary(array $issues): void
    {
        $this->newLine();

        if (empty($issues)) {
            $this->info('🎉 System health check passed! No issues found.');
            return;
        }

        $critical = array_filter($issues, fn($i) => $i['type'] === 'critical');
        $errors = array_filter($issues, fn($i) => $i['type'] === 'error');
        $warnings = array_filter($issues, fn($i) => $i['type'] === 'warning');

        $this->error('🚨 Issues found:');
        $this->line("   ❌ Critical: " . count($critical));
        $this->line("   🔴 Errors: " . count($errors));
        $this->line("   ⚠️ Warnings: " . count($warnings));

        if ($this->option('detailed')) {
            $this->newLine();
            $this->info('📋 Detailed Issues:');

            foreach ($issues as $issue) {
                $emoji = match($issue['type']) {
                    'critical' => '❌',
                    'error' => '🔴',
                    'warning' => '⚠️',
                    default => '📝'
                };

                $this->line("{$emoji} {$issue['message']}");

                if (isset($issue['details'])) {
                    $this->line("     Details: {$issue['details']}");
                }

                if (isset($issue['fix'])) {
                    $this->line("     Fix: {$issue['fix']}");
                }

                $this->newLine();
            }
        }

        $this->newLine();
        $this->warn('💡 Use --fix-issues to attempt automatic fixes');
        $this->warn('💡 Use --detailed to see full issue descriptions');
    }

    private function attemptFixes(array $issues): void
    {
        $this->info('🔧 Attempting to fix issues...');
        $this->newLine();

        foreach ($issues as $issue) {
            if (!isset($issue['fix']) || $issue['type'] === 'critical') {
                continue; // Skip critical issues or issues without auto-fix
            }

            $this->line("Fixing: {$issue['message']}");

            try {
                // Auto-fix orphaned records
                if (str_contains($issue['message'], 'orphaned records')) {
                    $deleted = DB::table('msgraph_pending_changes as mpc')
                        ->leftJoin('users as u', 'mpc.user_id', '=', 'u.id')
                        ->whereNull('u.id')
                        ->delete();

                    $this->line("   ✅ Cleaned up {$deleted} orphaned records");
                }

                // More auto-fixes can be added here

            } catch (\Exception $e) {
                $this->error("   ❌ Failed to fix: {$e->getMessage()}");
            }
        }

        $this->newLine();
        $this->info('🎉 Auto-fix completed. Re-run diagnostics to verify.');
    }
}
