<?php

namespace App\Console\Commands;

use App\Mail\CaseReportSummaryMail;
use App\Models\AlertRule;
use App\Models\CaseAlert;
use App\Models\CaseItem;
use App\Models\ReportDispatchLog;
use App\Models\User;
use Illuminate\Console\Command;
use Illuminate\Support\Facades\Mail;

class SendCaseReportAlertsCommand extends Command
{
    protected $signature = 'reports:send-alerts {--rule_id=} {--force} {--manual}';

    protected $description = 'Send automated case report emails based on configured rules';

    public function handle(): int
    {
        $now = now();
        $ruleId = $this->option('rule_id');
        $force = (bool) $this->option('force');
        $manual = (bool) $this->option('manual');

        $rules = AlertRule::query()
            ->when($ruleId, fn ($q) => $q->where('id', (int) $ruleId))
            ->where('enabled', true)
            ->get();

        foreach ($rules as $rule) {
            if (!$force && $rule->last_run_at && $rule->last_run_at->gt($now->copy()->subMinutes($rule->check_every_minutes))) {
                continue;
            }

            $scope = CaseItem::query();
            if (!$rule->is_global && $rule->client_id) {
                $scope->where('client_id', $rule->client_id);
            }
            if ($rule->track_date_from) {
                $scope->whereDate('post_date', '>=', $rule->track_date_from);
            }
            if ($rule->track_date_to) {
                $scope->whereDate('post_date', '<=', $rule->track_date_to);
            }

            $triggerQuery = (clone $scope)
                ->whereIn('status', $rule->statuses ?? []);

            if (!empty($rule->trigger_actions)) {
                $triggerQuery->whereIn('action_social', $rule->trigger_actions);
            }

            $triggerCases = $triggerQuery->with('client')->get();

            if (!$force && $triggerCases->isEmpty()) {
                $this->logRun($rule, 'no_trigger', 0, 0, $manual, 'No cases matched trigger conditions.');
                $rule->update(['last_run_at' => $now]);
                continue;
            }

            $summaryCases = (clone $scope)->with('client')->get();

            $summary = [
                'total' => $summaryCases->count(),
                'open' => $summaryCases->where('status', 'Open')->count(),
                'in_progress' => $summaryCases->where('status', 'In Progress')->count(),
                'waiting' => $summaryCases->where('status', 'Waiting for User')->count(),
                'resolved' => $summaryCases->where('status', 'Resolved')->count(),
                'closed' => $summaryCases->where('status', 'Closed')->count(),
                'critical' => $summaryCases->where('sentiment', 'Critical')->where('status', '!=', 'Closed')->count(),
            ];

            $statusBreakdown = $summaryCases
                ->groupBy('status')
                ->map(fn ($rows) => $rows->count())
                ->toArray();

            $sentimentBreakdown = $summaryCases
                ->groupBy('sentiment')
                ->map(fn ($rows) => $rows->count())
                ->toArray();

            $openCases = $summaryCases
                ->where('status', '!=', 'Closed')
                ->sortByDesc('updated_at')
                ->take(50)
                ->map(fn ($case) => [
                    'id' => $case->id,
                    'client' => $case->client?->name ?? '-',
                    'label' => $case->label,
                    'sentiment' => $case->sentiment,
                    'status' => $case->status,
                    'updated_at' => (string) $case->updated_at,
                    'url' => route('cases.show', $case),
                ])
                ->values()
                ->all();

            $closedCases = $summaryCases
                ->where('status', 'Closed')
                ->sortByDesc('closed_at')
                ->take(50)
                ->map(fn ($case) => [
                    'id' => $case->id,
                    'client' => $case->client?->name ?? '-',
                    'label' => $case->label,
                    'sentiment' => $case->sentiment,
                    'closed_at' => (string) ($case->closed_at ?? $case->updated_at),
                    'url' => route('cases.show', $case),
                ])
                ->values()
                ->all();

            $criticalCases = $summaryCases
                ->where('sentiment', 'Critical')
                ->sortByDesc('updated_at')
                ->take(50)
                ->map(fn ($case) => [
                    'id' => $case->id,
                    'client' => $case->client?->name ?? '-',
                    'label' => $case->label,
                    'status' => $case->status,
                    'updated_at' => (string) $case->updated_at,
                    'url' => route('cases.show', $case),
                ])
                ->values()
                ->all();

            $blocks = $rule->report_blocks ?: ['summary_kpis', 'open_cases_table', 'closed_cases_table'];
            if (!in_array('custom_message', $blocks, true)) {
                array_unshift($blocks, 'custom_message');
            }

            $renderedBody = $this->renderRuleTemplate($rule->email_body ?? '', $rule, $summary);
            $clientInfo = [
                'name' => $rule->client?->name ?? 'All Clients',
                'scope' => $rule->is_global ? 'Global' : 'Client-specific',
                'timezone' => $rule->client?->timezone ?? config('app.timezone'),
                'default_notification_emails' => $rule->client?->default_notification_emails ?? [],
                'date_from' => $rule->track_date_from?->format('Y-m-d') ?? 'N/A',
                'date_to' => $rule->track_date_to?->format('Y-m-d') ?? 'N/A',
            ];

            [$to, $cc] = $this->resolveRecipients($rule);

            if (count($to) === 0) {
                $this->logRun($rule, 'no_recipients', 0, $summary['total'], $manual, 'No recipient emails resolved.');
                $rule->update(['last_run_at' => $now]);
                continue;
            }

            try {
                $subject = str_replace('{case_id}', 'summary', $rule->email_subject ?: 'Automated Case Report');
                $mail = Mail::to($to);
                if (count($cc) > 0) {
                    $mail->cc($cc);
                }
                $mail->send(new CaseReportSummaryMail(
                    $rule,
                    $renderedBody,
                    $clientInfo,
                    $summary,
                    $statusBreakdown,
                    $sentimentBreakdown,
                    $criticalCases,
                    $openCases,
                    $closedCases,
                    $blocks,
                    $subject
                ));

                foreach ($triggerCases as $case) {
                    $latest = CaseAlert::query()
                        ->where('case_id', $case->id)
                        ->where('alert_rule_id', $rule->id)
                        ->latest('id')
                        ->first();

                    $nextNotifyAt = $rule->renotify_every_hours ? $now->copy()->addHours($rule->renotify_every_hours) : null;
                    $notifyCount = $latest ? ($latest->notify_count + 1) : 1;

                    if ($latest) {
                        $latest->update([
                            'notified_at' => $now,
                            'next_notify_at' => $nextNotifyAt,
                            'notify_count' => $notifyCount,
                        ]);
                    } else {
                        CaseAlert::create([
                            'case_id' => $case->id,
                            'alert_rule_id' => $rule->id,
                            'notified_at' => $now,
                            'next_notify_at' => $nextNotifyAt,
                            'notify_count' => 1,
                        ]);
                    }

                    $case->update([
                        'last_notified_at' => $now,
                        'escalation_state' => 'notified',
                    ]);
                }

                $this->logRun($rule, 'sent', count($to), $summary['total'], $manual, null);
            } catch (\Throwable $e) {
                $this->logRun($rule, 'failed', count($to), $summary['total'], $manual, $e->getMessage());
            }

            $rule->update(['last_run_at' => $now]);
        }

        $this->info('Report run completed.');

        return self::SUCCESS;
    }

    private function resolveRecipients(AlertRule $rule): array
    {
        $roles = $rule->recipients_roles ?? [];
        $to = [];

        if (count($roles) > 0) {
            $users = User::query()
                ->where('is_active', true)
                ->whereHas('roles', fn ($q) => $q->whereIn('name', $roles))
                ->when(!$rule->is_global && $rule->client_id, function ($query) use ($rule) {
                    $query->where(function ($q) use ($rule) {
                        $q->where('client_id', $rule->client_id)
                            ->orWhereHas('assignedClients', fn ($aq) => $aq->where('clients.id', $rule->client_id));
                    });
                })
                ->pluck('email')
                ->all();

            $to = array_merge($to, $users);
        }

        $to = array_merge($to, $rule->recipients_emails ?? []);
        $to = array_values(array_unique(array_filter($to)));

        $cc = [];
        if ($rule->cc_client && $rule->client) {
            $cc = $rule->client->default_notification_emails ?? [];
            $cc = array_values(array_unique(array_filter($cc)));
        }

        return [$to, $cc];
    }

    private function logRun(AlertRule $rule, string $status, int $recipientCount, int $caseCount, bool $manual, ?string $note): void
    {
        ReportDispatchLog::create([
            'alert_rule_id' => $rule->id,
            'ran_at' => now(),
            'status' => $status,
            'recipient_count' => $recipientCount,
            'case_count' => $caseCount,
            'is_manual' => $manual,
            'note' => $note,
        ]);
    }

    private function renderRuleTemplate(string $template, AlertRule $rule, array $summary): string
    {
        $replacements = [
            '{rule_name}' => $rule->name ?? '',
            '{scope}' => $rule->is_global ? 'Global' : 'Client',
            '{client_name}' => $rule->client?->name ?? 'All Clients',
            '{from_date}' => $rule->track_date_from ? (string) $rule->track_date_from->format('Y-m-d') : 'N/A',
            '{to_date}' => $rule->track_date_to ? (string) $rule->track_date_to->format('Y-m-d') : 'N/A',
            '{total_cases}' => (string) ($summary['total'] ?? 0),
            '{open_cases}' => (string) ($summary['open'] ?? 0),
            '{closed_cases}' => (string) ($summary['closed'] ?? 0),
            '{critical_cases}' => (string) ($summary['critical'] ?? 0),
            '{generated_at}' => now()->toDateTimeString(),
        ];

        return trim(strtr($template, $replacements));
    }
}
