<?php

namespace App\Services;

use App\Models\Agent;
use App\Models\Backup;
use App\Models\SiteHealthLog;
use App\Models\TableSnapshot;
use App\Models\Website;

class RemoteAgentService
{
    public function __construct(
        protected AgentCommunicationService $agentCommunication,
    ) {
    }

    public function synchronize(Website $website): array
    {
        if ($website->status === 'disabled') {
            return ['ok' => false, 'message' => 'Disabled websites are excluded from remote syncs.'];
        }

        $agent = $website->agent()->firstOrCreate([]);
        $result = $this->agentCommunication->healthCheck($website);

        if (! $result['ok']) {
            return $this->markUnavailable($website, $agent, $result['message'], $result['latency']);
        }

        $payload = $result['payload'] ?? [];
        $latency = $result['latency'] ?? null;
        $verified = $this->verifyAgentPayload($payload);
        $tableSync = $this->agentCommunication->fetchTables($website);
        $syncedTableCount = $this->syncTableSnapshots($website, $tableSync['payload']['tables'] ?? []);

        $website->update([
            'status' => $payload['status'] ?? 'online',
            'health_status' => $payload['health'] ?? 'healthy',
            'database_count' => $payload['database_count'] ?? $website->database_count,
            'table_count' => $tableSync['ok']
                ? $syncedTableCount
                : ($payload['table_count'] ?? $website->table_count),
            'response_time_ms' => $latency,
            'last_seen_at' => now(),
            'last_synced_at' => now(),
        ]);

        $agent->update([
            'version' => $payload['version'] ?? $agent->version,
            'status' => $payload['status'] ?? 'online',
            'authentication_status' => $verified ? 'verified' : 'pending',
            'sync_status' => $verified ? 'synced' : 'pending',
            'latency_ms' => $latency,
            'last_heartbeat_at' => now(),
            'capabilities' => $payload['capabilities'] ?? $agent->capabilities,
            'heartbeat_payload' => $payload,
        ]);

        SiteHealthLog::query()->create([
            'website_id' => $website->id,
            'status' => $payload['status'] ?? 'online',
            'health_status' => $payload['health'] ?? 'healthy',
            'response_time_ms' => $latency,
            'message' => $verified
                ? ($tableSync['ok']
                    ? 'Health check passed, table inventory synced, and agent verification succeeded.'
                    : 'Health check passed and agent verification succeeded, but table sync is pending.')
                : 'Health check passed, but agent verification is incomplete.',
            'payload' => [
                ...$payload,
                'tables_synced' => $syncedTableCount,
                'table_sync_ok' => $tableSync['ok'],
            ],
            'checked_at' => now(),
        ]);

        return [
            'ok' => true,
            'message' => $verified
                ? ($tableSync['ok']
                    ? 'Health check passed, website synced, and agent verified successfully.'
                    : 'Health check passed and the agent was verified, but table metadata sync is still pending.')
                : 'Health check passed, but the agent did not expose all expected capabilities.',
        ];
    }

    public function requestBackup(Website $website, Backup $backup, array $payload = []): array
    {
        $result = $this->agentCommunication->requestBackup($website, [
            'panel_backup_id' => $backup->id,
            'requested_by' => $backup->initiatedBy?->email,
            ...$payload,
        ]);

        return [
            'ok' => $result['ok'],
            'message' => $result['ok']
                ? 'Remote agent created the backup successfully.'
                : 'Agent backup request failed: '.$result['message'],
            'payload' => $result['payload'] ?? [],
        ];
    }

    public function restoreBackup(Website $website, Backup $backup): array
    {
        $reference = (string) ($backup->id);
        $result = $this->agentCommunication->restoreBackup($website, $reference, [
            'panel_backup_id' => $backup->id,
        ]);

        return [
            'ok' => $result['ok'],
            'message' => $result['ok']
                ? 'Remote agent accepted the restore request.'
                : 'Agent restore request failed: '.$result['message'],
            'payload' => $result['payload'] ?? [],
        ];
    }

    protected function markUnavailable(Website $website, Agent $agent, string $reason, ?int $latency = null): array
    {
        $website->update([
            'status' => $website->status === 'disabled' ? 'disabled' : 'offline',
            'health_status' => 'critical',
            'response_time_ms' => $latency,
            'last_synced_at' => now(),
        ]);

        $agent->update([
            'status' => 'offline',
            'authentication_status' => 'pending',
            'sync_status' => 'stale',
            'last_heartbeat_at' => now(),
            'heartbeat_payload' => ['error' => $reason],
        ]);

        SiteHealthLog::query()->create([
            'website_id' => $website->id,
            'status' => $website->status,
            'health_status' => 'critical',
            'response_time_ms' => $latency,
            'message' => $reason,
            'payload' => ['error' => $reason],
            'checked_at' => now(),
        ]);

        return ['ok' => false, 'message' => 'Agent sync failed: '.$reason];
    }

    protected function verifyAgentPayload(array $payload): bool
    {
        $capabilities = collect($payload['capabilities'] ?? []);

        return $capabilities->contains('health')
            && $capabilities->contains('tables')
            && ($payload['status'] ?? null) === 'online';
    }

    protected function syncTableSnapshots(Website $website, array $tables): int
    {
        if ($tables === []) {
            return 0;
        }

        $tableNames = [];

        foreach ($tables as $table) {
            $tableName = (string) ($table['table_name'] ?? '');

            if ($tableName === '') {
                continue;
            }

            $tableNames[] = $tableName;

            TableSnapshot::query()->updateOrCreate(
                [
                    'website_id' => $website->id,
                    'table_name' => $tableName,
                ],
                [
                    'row_count' => (int) ($table['row_count'] ?? 0),
                    'size_bytes' => (int) ($table['size_bytes'] ?? 0),
                    'last_updated_at' => $table['last_updated_at'] ?? now(),
                    'structure' => $table['structure'] ?? null,
                ],
            );
        }

        if ($tableNames !== []) {
            TableSnapshot::query()
                ->where('website_id', $website->id)
                ->whereNotIn('table_name', $tableNames)
                ->delete();
        }

        return count($tableNames);
    }
}
