<?php

namespace App\Services\MicrosoftGraph;

use App\Models\Committee;
use App\Models\Contact;
use App\Models\ContactFolder;
use App\Services\MicrosoftGraph\MicrosoftGraphApiClient;
use App\Services\MicrosoftGraph\MicrosoftGraphUtilities;
use App\Models\MicrosoftUser;
use App\Models\WorkGroup;
use Illuminate\Support\Facades\Log;
use Illuminate\Support\Facades\Schema;
use Exception;

/**
 * Service for Microsoft Graph testing and diagnostic operations
 * Handles test operations, diagnostics, and development utilities
 */
class MicrosoftGraphTestService
{
    protected $apiClient;

    public function __construct(MicrosoftGraphApiClient $apiClient)
    {
        $this->apiClient = $apiClient;
    }

    /**
     * Test Microsoft Graph connection
     */
    public function testConnection(): array
    {
        return $this->apiClient->testConnection();
    }

    /**
     * Create a test contact folder for testing purposes
     */
    public function createTestContactFolder(string $folderName = 'Test-Contact-Folder'): array
    {
        MicrosoftGraphUtilities::logOperation('info', "Creating test contact folder: {$folderName}");

        $result = [
            'status' => 'error',
            'message' => 'Unknown error',
            'folder_id' => null,
            'folder_name' => $folderName,
            'service_users_tested' => []
        ];

        try {
            // Get all service users for comprehensive testing
            $serviceUsers = MicrosoftUser::whereNotNull('ms_id')->where('ms_id', '!=', '')->get();
            if ($serviceUsers->isEmpty()) {
                throw new Exception('No service users found for Microsoft Graph operations');
            }

            // Test with the first service user (primary test)
            $primaryUser = $serviceUsers->first();
            $sanitizedName = MicrosoftGraphUtilities::sanitizeFolderDisplayName($folderName);

            $folderData = [
                'displayName' => $sanitizedName
            ];

            $graphService = $this->apiClient->getGraphService();
            $response = $graphService->post("users/{$primaryUser->email}/contactFolders", $folderData);

            if (!$response) {
                throw new Exception('Failed to create test contact folder');
            }

            $folderId = $this->apiClient->getResponseValue($response, 'id');
            $displayName = $this->apiClient->getResponseValue($response, 'displayName');

            $result['status'] = 'success';
            $result['message'] = 'Test contact folder created successfully';
            $result['folder_id'] = $folderId;
            $result['folder_name'] = $displayName;
            $result['service_user_id'] = $primaryUser->id;
            $result['service_user_email'] = $primaryUser->email;

            // Test connection for all service users
            foreach ($serviceUsers as $user) {
                try {
                    $testResponse = $graphService->get("users/{$user->email}/contactFolders");
                    $result['service_users_tested'][] = [
                        'id' => $user->id,
                        'email' => $user->email,
                        'name' => $user->title,
                        'status' => 'success',
                        'folder_count' => count($testResponse['value'] ?? [])
                    ];
                } catch (Exception $e) {
                    $result['service_users_tested'][] = [
                        'id' => $user->id,
                        'email' => $user->email,
                        'name' => $user->title,
                        'status' => 'error',
                        'error' => $e->getMessage()
                    ];
                }
            }

            MicrosoftGraphUtilities::logOperation('success', "Created test folder: {$displayName}", [
                'folder_id' => $folderId,
                'tested_users' => count($result['service_users_tested'])
            ]);

        } catch (Exception $e) {
            $result['message'] = 'Failed to create test contact folder: ' . $e->getMessage();
            MicrosoftGraphUtilities::logOperation('error', 'Test folder creation failed', [
                'error' => $e->getMessage()
            ]);
        }

        return $result;
    }

    /**
     * Delete a test contact folder
     */
    public function deleteTestContactFolder(string $folderId, string $userEmail = null): array
    {
        MicrosoftGraphUtilities::logOperation('info', "Deleting test contact folder: {$folderId}");

        $result = [
            'status' => 'error',
            'message' => 'Unknown error',
            'folder_id' => $folderId
        ];

        try {
            // If user email not provided, try to find which user has this folder
            if (!$userEmail) {
                $serviceUsers = MicrosoftUser::whereNotNull('ms_id')->where('ms_id', '!=', '')->get();
                if ($serviceUsers->isEmpty()) {
                    throw new Exception('No service users found for Microsoft Graph operations');
                }

                // Try to find the folder in each user's contact folders
                $foundUser = null;
                foreach ($serviceUsers as $user) {
                    try {
                        $graphService = $this->apiClient->getGraphService();
                        $response = $graphService->get("users/{$user->email}/contactFolders/{$folderId}");
                        if ($response) {
                            $foundUser = $user;
                            break;
                        }
                    } catch (Exception $e) {
                        // Folder not found in this user, continue
                        continue;
                    }
                }

                if (!$foundUser) {
                    throw new Exception('Test folder not found in any service user account');
                }

                $userEmail = $foundUser->email;
            }

            $graphService = $this->apiClient->getGraphService();
            $response = $graphService->post("users/{$userEmail}/contactFolders/{$folderId}/permanentDelete", []);

            $result['status'] = 'success';
            $result['message'] = 'Test contact folder deleted successfully';
            $result['user_email'] = $userEmail;

            MicrosoftGraphUtilities::logOperation('success', "Deleted test folder: {$folderId} from user: {$userEmail}");

        } catch (Exception $e) {
            $result['message'] = 'Failed to delete test contact folder: ' . $e->getMessage();
            MicrosoftGraphUtilities::logOperation('error', 'Test folder deletion failed', [
                'folder_id' => $folderId,
                'user_email' => $userEmail,
                'error' => $e->getMessage()
            ]);
        }

        return $result;
    }

    /**
     * Get comprehensive statistics about the sync system
     */
    public function getStats(): array
    {
        MicrosoftGraphUtilities::logOperation('info', 'Gathering Microsoft Graph sync statistics');

        try {
            $stats = [
                'database' => $this->getDatabaseStats(),
                'microsoft_graph' => $this->getMicrosoftGraphStats(),
                'sync_status' => $this->getSyncStatus()
            ];

            return $stats;

        } catch (Exception $e) {
            MicrosoftGraphUtilities::logOperation('error', 'Failed to gather stats', [
                'error' => $e->getMessage()
            ]);

            return [
                'error' => 'Failed to gather statistics: ' . $e->getMessage(),
                'database' => [],
                'microsoft_graph' => [],
                'sync_status' => []
            ];
        }
    }

    /**
     * Get database statistics
     */
    protected function getDatabaseStats(): array
    {
        return [
            'contact_folders' => [
                'total' => ContactFolder::count(),
                'with_ms_id' => ContactFolder::whereNotNull('ms_folder_id')->count(),
                'by_type' => [
                    'TO' => ContactFolder::where('folder_type', 'TO')->count(),
                    'CC' => ContactFolder::where('folder_type', 'CC')->count(),
                ]
            ],
            'contacts' => [
                'total' => Contact::count(),
                'with_ms_id' => Contact::whereNotNull('ms_contact_id')->count(),
            ],
            'committees' => [
                'total' => Committee::count(),
                'published' => Committee::select('committees.*')
                    ->join('website_objects', function ($join) {
                        $join->on('website_objects.object_id', '=', 'committees.id')
                             ->where('website_objects.object_type', '=', 'committee');
                    })
                    ->where('website_objects.status', 'published')
                    ->count()
            ],
            'workgroups' => [
                'total' => WorkGroup::count(),
                'published' => WorkGroup::select('work_groups.*')
                    ->join('website_objects', function ($join) {
                        $join->on('website_objects.object_id', '=', 'work_groups.id')
                             ->where('website_objects.object_type', '=', 'workgroup');
                    })
                    ->where('website_objects.status', 'published')
                    ->count()
            ],
            'microsoft_users' => [
                'total' => MicrosoftUser::count(),
                'service_users' => MicrosoftUser::whereNotNull('ms_id')->where('ms_id', '!=', '')->count(),
            ]
        ];
    }

    /**
     * Get Microsoft Graph statistics
     */
    protected function getMicrosoftGraphStats(): array
    {
        try {
            if ($this->apiClient->isDryRun()) {
                return ['status' => 'dry_run_mode'];
            }

            $serviceUser = MicrosoftUser::whereNotNull('ms_id')->where('ms_id', '!=', '')->first();
            if (!$serviceUser) {
                return ['error' => 'No service user found'];
            }

            $folders = $this->apiClient->getAllPaginatedItems("users/{$serviceUser->email}/contactFolders");

            $totalContacts = 0;
            foreach ($folders as $folder) {
                $folderId = $this->apiClient->getResponseValue($folder, 'id');
                $contacts = $this->apiClient->getAllPaginatedItems("users/{$serviceUser->email}/contactFolders/{$folderId}/contacts");
                $totalContacts += count($contacts);
            }

            return [
                'folders' => count($folders),
                'contacts' => $totalContacts,
                'service_user' => $serviceUser->email
            ];

        } catch (Exception $e) {
            return ['error' => 'Failed to get Microsoft Graph stats: ' . $e->getMessage()];
        }
    }

    /**
     * Get sync status information
     */
    protected function getSyncStatus(): array
    {
        $lastSync = ContactFolder::latest('updated_at')->first();

        return [
            'last_sync' => $lastSync ? $lastSync->updated_at->toISOString() : null,
            'folders_missing_ms_id' => ContactFolder::whereNull('ms_folder_id')->count(),
            'contacts_missing_ms_id' => Contact::whereNull('ms_contact_id')->count(),
            'connection_available' => MicrosoftGraphApiClient::isAvailable()
        ];
    }

    /**
     * Run comprehensive diagnostics
     */
    public function runDiagnostics(): array
    {
        MicrosoftGraphUtilities::logOperation('info', 'Running comprehensive diagnostics');

        $diagnostics = [
            'connection_test' => $this->testConnection(),
            'stats' => $this->getStats(),
            'checks' => $this->runSystemChecks()
        ];

        return $diagnostics;
    }

    /**
     * Run system checks
     */
    protected function runSystemChecks(): array
    {
        $checks = [];

        // Check if service user exists
        $serviceUser = MicrosoftUser::whereNotNull('ms_id')->where('ms_id', '!=', '')->first();
        $checks['service_user'] = [
            'status' => $serviceUser ? 'pass' : 'fail',
            'message' => $serviceUser ? 'Service user found' : 'No service user found',
            'details' => $serviceUser ? ['email' => $serviceUser->email] : []
        ];

        // Check if tables exist
        $tables = ['contact_folders', 'contacts', 'committees', 'work_groups', 'microsoft_users'];
        foreach ($tables as $table) {
            $exists = Schema::hasTable($table);
            $checks["table_{$table}"] = [
                'status' => $exists ? 'pass' : 'fail',
                'message' => $exists ? "Table {$table} exists" : "Table {$table} missing"
            ];
        }

        // Check for orphaned records
        $orphanedFolders = ContactFolder::whereDoesntHave('contactable')->count();
        $checks['orphaned_folders'] = [
            'status' => $orphanedFolders === 0 ? 'pass' : 'warning',
            'message' => $orphanedFolders === 0 ? 'No orphaned folders' : "{$orphanedFolders} orphaned folders found",
            'count' => $orphanedFolders
        ];

        $orphanedContacts = Contact::whereDoesntHave('contactFolder')->count();
        $checks['orphaned_contacts'] = [
            'status' => $orphanedContacts === 0 ? 'pass' : 'warning',
            'message' => $orphanedContacts === 0 ? 'No orphaned contacts' : "{$orphanedContacts} orphaned contacts found",
            'count' => $orphanedContacts
        ];

        return $checks;
    }
}
