<?php

namespace App\Services;

use Illuminate\Support\Facades\Cache;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Log;
use Carbon\Carbon;

class CampaignHealthService
{
    /**
     * Diagnose why a campaign is or isn't running.
     *
     * Priority order (first match wins):
     *   1. Campaign deleted        → hard block, nothing to do
     *   2. Campaign paused by system (pause_reason set) → actionable
     *   3. Campaign paused manually (status=0, no pause_reason) → user action
     *   4. Wallet balance <= 0     → recharge needed
     *   5. No leads in hopper      → add leads
     *   6. Cron not running        → system issue
     *   7. All clear               → running
     */
    public static function diagnose(int $clientId, int $campaignId): array
    {
        try {
            $conn = DB::connection('mysql_' . $clientId);

            // ── 1. Fetch campaign ──
            $campaign = $conn->table('campaign')
                ->where('id', $campaignId)
                ->first();

            if (!$campaign) {
                return self::result('NOT_FOUND', 'CAMPAIGN_NOT_FOUND',
                    'Campaign not found.',
                    'Check campaign ID or contact support.');
            }

            if ($campaign->is_deleted == 1) {
                return self::result('NOT_FOUND', 'CAMPAIGN_DELETED',
                    'This campaign has been deleted.',
                    'Create a new campaign.');
            }

            // Only relevant for outbound_ai campaigns
            if ($campaign->dial_mode !== 'outbound_ai') {
                return self::result('NOT_APPLICABLE', 'NOT_OUTBOUND_AI',
                    'Health check is only available for Outbound AI campaigns.',
                    null);
            }

            // ── 2. Campaign paused by system (has pause_reason) ──
            if ($campaign->status == 0 && !empty($campaign->pause_reason)) {
                return self::systemPauseResult($campaign->pause_reason);
            }

            // ── 3. Campaign paused manually ──
            if ($campaign->status == 0) {
                return self::result('PAUSED', 'PAUSED_MANUALLY',
                    'Campaign is paused. It was turned off manually.',
                    'Resume the campaign to start calls.');
            }

            // ── At this point campaign status = 1 (active). Check if it CAN actually run. ──

            // ── 4. Wallet balance ──
            $walletBalance = (float) ($conn->table('wallet')->value('amount') ?? 0);
            if ($walletBalance <= 0) {
                return self::result('BLOCKED', 'INSUFFICIENT_WALLET',
                    'Wallet balance is ' . number_format($walletBalance, 2) . '. Calls cannot be placed.',
                    'Recharge your wallet to resume calls.');
            }

            // ── 5. No leads available ──
            $leadCount = $conn->table('lead_temp')
                ->where('campaign_id', $campaignId)
                ->count();

            $hasLists = $conn->table('campaign_list')
                ->where('campaign_id', $campaignId)
                ->where('status', 1)
                ->where('is_deleted', 0)
                ->exists();

            if (!$hasLists) {
                return self::result('BLOCKED', 'NO_LISTS_ASSIGNED',
                    'No active lists are assigned to this campaign.',
                    'Assign a list with leads to this campaign.');
            }

            if ($leadCount == 0) {
                // Check if all leads have already been called
                $totalLeadsInLists = $conn->table('campaign_list')
                    ->where('campaign_id', $campaignId)
                    ->where('status', 1)
                    ->where('is_deleted', 0)
                    ->join('list_data', 'campaign_list.list_id', '=', 'list_data.list_id')
                    ->count();

                $calledLeads = $conn->table('lead_report')
                    ->where('campaign_id', $campaignId)
                    ->count();

                if ($totalLeadsInLists > 0 && $calledLeads >= $totalLeadsInLists) {
                    return self::result('IDLE', 'ALL_LEADS_CALLED',
                        'All leads in this campaign have been called.',
                        'Add new leads or reset the campaign to call again.');
                }

                return self::result('IDLE', 'NO_LEADS_IN_HOPPER',
                    'No leads are currently queued for dialing. The system will reload leads automatically.',
                    'Wait for the next cron cycle, or add more leads.');
            }

            // ── 6. Cron health ──
            $lastCronRun = Cache::get('outbound_cron_last_run');
            if ($lastCronRun) {
                $minutesSinceLastRun = Carbon::parse($lastCronRun)->diffInMinutes(now());
                if ($minutesSinceLastRun > 5) {
                    return self::result('SYSTEM_ISSUE', 'CRON_STALE',
                        'The outbound calling system has not run for ' . $minutesSinceLastRun . ' minutes.',
                        'Contact support — the outbound cron may need to be restarted.');
                }
            } else {
                return self::result('SYSTEM_ISSUE', 'CRON_NEVER_RAN',
                    'The outbound calling system has not started yet.',
                    'Contact support — the outbound cron may not be configured.');
            }

            // ── 7. All checks passed ──
            return self::result('RUNNING', 'HEALTHY',
                'Campaign is active and running. Wallet balance: ' . number_format($walletBalance, 2) . '. Leads queued: ' . $leadCount . '.',
                null);

        } catch (\Throwable $e) {
            Log::error('CampaignHealthService error', [
                'client_id'   => $clientId,
                'campaign_id' => $campaignId,
                'error'       => $e->getMessage(),
            ]);

            return self::result('SYSTEM_ISSUE', 'HEALTH_CHECK_FAILED',
                'Unable to check campaign health. Please try again.',
                'Contact support if the problem persists.');
        }
    }

    /**
     * Map system pause_reason to user-friendly response.
     */
    private static function systemPauseResult(string $pauseReason): array
    {
        $map = [
            'insufficient_wallet' => [
                'status'      => 'BLOCKED',
                'message'     => 'Campaign was automatically paused because your wallet balance ran out.',
                'action_hint' => 'Recharge your wallet — campaigns will resume automatically.',
            ],
            'ai_quota_exhausted' => [
                'status'      => 'SYSTEM_ISSUE',
                'message'     => 'Campaign was paused because the AI service quota was exhausted.',
                'action_hint' => 'Contact support — this is a system-level issue being resolved.',
            ],
            'no_subscription' => [
                'status'      => 'BLOCKED',
                'message'     => 'Campaign was paused because your subscription has expired.',
                'action_hint' => 'Renew your subscription to resume campaigns.',
            ],
        ];

        if (isset($map[$pauseReason])) {
            $entry = $map[$pauseReason];
            return self::result($entry['status'], strtoupper($pauseReason), $entry['message'], $entry['action_hint']);
        }

        return self::result('PAUSED', strtoupper($pauseReason),
            'Campaign was paused by the system. Reason: ' . $pauseReason,
            'Contact support for details.');
    }

    /**
     * Build a standardized response array.
     */
    private static function result(string $status, string $reasonCode, string $message, ?string $actionHint): array
    {
        return [
            'status'      => $status,
            'reason_code' => $reasonCode,
            'message'     => $message,
            'action_hint' => $actionHint,
        ];
    }
}
