<?php
require_once __DIR__ . '/../Core.php';
require_once __DIR__ . '/../services.php';
require_once __DIR__ . '/../models/Message.php';
require_once __DIR__ . '/../models/Contact.php';
require_once __DIR__ . '/../models/Template.php';
require_once __DIR__ . '/../models/Campaign.php';
require_once __DIR__ . '/../models/Segment.php';
require_once __DIR__ . '/../models/Suppression.php';
require_once __DIR__ . '/../models/CannedReply.php';
require_once __DIR__ . '/../models/ConversationState.php';
require_once __DIR__ . '/../models/User.php';
require_once __DIR__ . '/../models/QueueJob.php';
require_once __DIR__ . '/../models/ContactList.php';

class MessagesController extends Controller
{
    public function index(): void
    {
        require_permission('messages.view');
        $filters = [
            'q' => trim($_GET['q'] ?? ''),
            'channel' => $_GET['channel'] ?? 'all',
            'direction' => $_GET['direction'] ?? 'all',
            'status' => $_GET['status'] ?? 'all',
        ];
        $page = max(1, (int)($_GET['page'] ?? 1));
        $messageModel = new Message();
        $campaignModel = new Campaign();
        $queueModel = new QueueJob();
        $suppressionModel = new Suppression();
        $providerStatus = provider_status_summary();
        $conversationResult = $messageModel->conversationSummary($filters, $page, 15);
        $selectedConversation = $_GET['conversation'] ?? ($conversationResult['data'][0]['conversation_key'] ?? null);
        $thread = $selectedConversation ? $messageModel->thread($selectedConversation) : [];
        $result = $messageModel->search($filters, $page, 25);
        $templates = (new Template())->all();
        $analytics = $messageModel->analyticsDaily(21);
        $healthSummary = $messageModel->healthSummary(30);
        $suppressionSummary = $suppressionModel->summary(30);
        $queueStats = $queueModel->stats();
        $lastMessage = $thread ? end($thread) : null;
        $campaigns = $campaignModel->all();
        $this->view('messages/index', [
            'smsTemplates' => (new Template())->all('sms'),
            'emailTemplates' => (new Template())->all('email'),
            'messages' => $result['data'],
            'meta' => $result['meta'],
            'filters' => $filters,
            'contacts' => (new Contact())->all(),
            'templates' => $templates,
            'campaigns' => $campaigns,
            'segments' => (new Segment())->all(),
            'contactLists' => (new ContactList())->all(),
            'templateJson' => json_encode($templates),
            'campaignContextJson' => json_encode([
                'providerStatus' => $providerStatus,
                'systemHealth' => [
                    'bounceRate' => (float)($healthSummary['bounce_rate'] ?? 0),
                    'queuePressure' => (float)($healthSummary['queue_pressure'] ?? 0),
                ],
                'timezone' => config('app.timezone', 'America/Chicago'),
            ]),
            'conversations' => $conversationResult['data'],
            'conversationMeta' => $conversationResult['meta'],
            'selectedConversation' => $selectedConversation,
            'thread' => $thread,
            'lastMessage' => $lastMessage,
            'analytics' => $analytics,
            'healthSummary' => $healthSummary,
            'providerStatus' => $providerStatus,
            'suppressionSummary' => $suppressionSummary,
            'suppressionRecent' => $suppressionModel->recent(8),
            'queueStats' => $queueStats,
            'failedQueueJobs' => $queueModel->failed(8),
            'deliverabilityAlerts' => $this->buildDeliverabilityAlerts($healthSummary, $queueStats, $suppressionSummary, $providerStatus),
            'cannedReplies' => (new CannedReply())->all($lastMessage['channel'] ?? null),
            'conversationState' => $selectedConversation ? (new ConversationState())->findByKey($selectedConversation) : null,
            'users' => (new User())->all(),
            'campaignComparison' => $campaignModel->compareRecent(8),
            'templatePerformance' => $campaignModel->templatePerformance(8),
            'segmentPerformance' => $campaignModel->segmentPerformance(8),
        ]);
    }

    public function sendSms(): void
    {
        require_permission('messages.send');
        verify_csrf();
        $contactId = (int)($_POST['contact_id'] ?? 0);
        $contact = $contactId ? (new Contact())->find($contactId) : null;
        $to = $contact['phone'] ?? trim($_POST['to_address'] ?? '');
        $body = apply_sms_preferences($_POST['body'] ?? '', (int)(current_user()['id'] ?? 0));
        $mediaUrl = trim($_POST['media_url'] ?? '') ?: null;
        try {
            if ((new Suppression())->isSuppressed('sms', $to)) {
                throw new RuntimeException('This SMS recipient is on the suppression list.');
            }
            $timezone = $contact['timezone'] ?? quiet_hours_settings()['timezone'];
            if (is_within_quiet_hours($timezone)) {
                throw new RuntimeException(quiet_hours_notice($timezone));
            }
            $twilio = new TwilioService();
            $result = $twilio->sendSms($to, $body, $mediaUrl);
            $messageId = (new Message())->create([
                'contact_id' => $contactId ?: null,
                'channel' => 'sms',
                'direction' => 'outbound',
                'body' => $body,
                'from_address' => effective_twilio_config((int)(current_user()['id'] ?? 0))['from_number'],
                'to_address' => $to,
                'status' => $result['status'] ?? 'sent',
                'external_id' => $result['sid'] ?? null,
                'media_url' => $mediaUrl,
                'metadata_json' => json_encode($result),
            ]);
            audit_log('message.sent', 'message', $messageId, ['channel' => 'sms']);
            flash('success', 'SMS/MMS sent successfully.');
        } catch (Throwable $e) {
            flash('error', $e->getMessage());
        }
        redirect('messages/index');
    }

    public function sendEmail(): void
    {
        require_permission('messages.send');
        verify_csrf();
        $contactId = (int)($_POST['contact_id'] ?? 0);
        $contact = $contactId ? (new Contact())->find($contactId) : null;
        $to = $contact['email'] ?? trim($_POST['to_address'] ?? '');
        $subject = $_POST['subject'] ?? '';
        $body = apply_email_preferences($_POST['body'] ?? '', (int)(current_user()['id'] ?? 0));
        $attachments = [];
        try {
            if ((new Suppression())->isSuppressed('email', $to)) {
                throw new RuntimeException('This email recipient is on the suppression list.');
            }
            $timezone = $contact['timezone'] ?? quiet_hours_settings()['timezone'];
            if (is_within_quiet_hours($timezone)) {
                throw new RuntimeException(quiet_hours_notice($timezone));
            }
            if (!empty($_FILES['attachment']['name'])) {
                $saved = upload_file($_FILES['attachment'], ['pdf', 'doc', 'docx', 'jpg', 'jpeg', 'png', 'gif']);
                if ($saved) {
                    $attachments[] = uploaded_file_path($saved);
                }
            }
            $messageModel = new Message();
            $messageId = $messageModel->create([
                'contact_id' => $contactId ?: null,
                'channel' => 'email',
                'direction' => 'outbound',
                'subject' => $subject,
                'body' => $body,
                'from_address' => effective_mail_config((int)(current_user()['id'] ?? 0))['from_email'],
                'to_address' => $to,
                'status' => 'queued',
                'attachment_path' => isset($saved) ? $saved : null,
            ]);
            $trackedHtml = instrument_email_html($body, $messageId);
            $externalId = '<msg-' . $messageId . '@' . parse_url(config('app.base_url'), PHP_URL_HOST) . '>';
            $mailConfig = effective_mail_config((int)(current_user()['id'] ?? 0));
            $ok = (new EmailService())->sendEmail($to, $subject, $trackedHtml, strip_tags($body), $attachments, ['Message-ID: ' . $externalId, 'Reply-To: ' . $mailConfig['reply_to_email']]);
            if (!$ok) {
                throw new RuntimeException('Email send failed. Check SMTP or server mail settings.');
            }
            $messageModel->updateExternalAndStatus($messageId, $externalId, 'sent', null);
            audit_log('message.sent', 'message', $messageId, ['channel' => 'email']);
            flash('success', 'Email sent successfully.');
        } catch (Throwable $e) {
            flash('error', $e->getMessage());
        }
        redirect('messages/index');
    }

    public function reply(): void
    {
        require_permission('messages.reply');
        verify_csrf();
        $channel = $_POST['channel'] ?? 'sms';
        $conversationKey = $_POST['conversation_key'] ?? '';
        $thread = (new Message())->thread($conversationKey);
        $last = $thread ? end($thread) : null;
        if (!$last) {
            flash('error', 'Conversation not found.');
            redirect('messages/index');
        }
        try {
            if ($channel === 'sms') {
                $to = $last['direction'] === 'inbound' ? $last['from_address'] : $last['to_address'];
                if ((new Suppression())->isSuppressed('sms', $to)) {
                    throw new RuntimeException('This SMS recipient is on the suppression list.');
                }
                $contact = !empty($last['contact_id']) ? (new Contact())->find((int)$last['contact_id']) : null;
                $timezone = $contact['timezone'] ?? quiet_hours_settings()['timezone'];
                if (is_within_quiet_hours($timezone)) {
                    throw new RuntimeException(quiet_hours_notice($timezone));
                }
                $body = apply_sms_preferences($_POST['body'] ?? '', (int)(current_user()['id'] ?? 0));
                $result = (new TwilioService())->sendSms($to, $body, null);
                $messageId = (new Message())->create([
                    'contact_id' => $last['contact_id'] ?: null,
                    'channel' => 'sms',
                    'direction' => 'outbound',
                    'body' => $body,
                    'from_address' => effective_twilio_config((int)(current_user()['id'] ?? 0))['from_number'],
                    'to_address' => $to,
                    'status' => $result['status'] ?? 'sent',
                    'external_id' => $result['sid'] ?? null,
                    'metadata_json' => json_encode($result),
                    'thread_key' => $conversationKey,
                ]);
            } else {
                $to = normalize_address($last['direction'] === 'inbound' ? $last['from_address'] : $last['to_address']);
                if ((new Suppression())->isSuppressed('email', $to)) {
                    throw new RuntimeException('This email recipient is on the suppression list.');
                }
                $contact = !empty($last['contact_id']) ? (new Contact())->find((int)$last['contact_id']) : null;
                $timezone = $contact['timezone'] ?? quiet_hours_settings()['timezone'];
                if (is_within_quiet_hours($timezone)) {
                    throw new RuntimeException(quiet_hours_notice($timezone));
                }
                $subject = trim($_POST['subject'] ?? ('Re: ' . ($last['subject'] ?? 'Conversation')));
                $body = apply_email_preferences($_POST['body'] ?? '', (int)(current_user()['id'] ?? 0));
                $messageModel = new Message();
                $messageId = $messageModel->create([
                    'contact_id' => $last['contact_id'] ?: null,
                    'channel' => 'email',
                    'direction' => 'outbound',
                    'subject' => $subject,
                    'body' => $body,
                    'from_address' => effective_mail_config((int)(current_user()['id'] ?? 0))['from_email'],
                    'to_address' => $to,
                    'status' => 'queued',
                    'thread_key' => $conversationKey,
                    'in_reply_to_external_id' => $last['external_id'] ?? null,
                    'references_header' => trim(($last['references_header'] ?? '') . ' ' . ($last['external_id'] ?? '')),
                ]);
                $trackedHtml = instrument_email_html($body, $messageId);
                $externalId = '<msg-' . $messageId . '@' . parse_url(config('app.base_url'), PHP_URL_HOST) . '>';
                $mailConfig = effective_mail_config((int)(current_user()['id'] ?? 0));
                $headers = ['Message-ID: ' . $externalId, 'Reply-To: ' . $mailConfig['reply_to_email']];
                if (!empty($last['external_id'])) {
                    $headers[] = 'In-Reply-To: ' . $last['external_id'];
                    $headers[] = 'References: ' . trim(($last['references_header'] ?? '') . ' ' . $last['external_id']);
                }
                (new EmailService())->sendEmail($to, $subject, $trackedHtml, strip_tags($body), [], $headers);
                $messageModel->updateExternalAndStatus($messageId, $externalId, 'sent', null);
            }
            audit_log('message.replied', 'message', $messageId ?? null, ['channel' => $channel, 'conversation_key' => $conversationKey]);
            flash('success', 'Reply sent.');
        } catch (Throwable $e) {
            flash('error', $e->getMessage());
        }
        redirect_url('index.php?route=messages/index&conversation=' . urlencode($conversationKey));
    }

    public function createCampaign(): void
    {
        require_permission('messages.campaigns');
        verify_csrf();
        try {
            $result = (new CampaignService())->queueCampaign($_POST);
            $message = 'Campaign saved. Campaign ID: ' . (int)$result['id'];
            if (!empty($result['preflight']['warnings'])) {
                $message .= ' Preflight notes: ' . implode(' ', array_slice($result['preflight']['warnings'], 0, 2));
            }
            flash('success', $message);
        } catch (Throwable $e) {
            flash('error', $e->getMessage());
        }
        redirect('messages/index');
    }

    public function approveCampaign(): void
    {
        require_permission('messages.campaigns');
        $id = (int)($_GET['id'] ?? 0);
        $campaign = (new Campaign())->find($id);
        if (!$campaign) {
            flash('error', 'Campaign not found.');
            redirect('messages/index');
        }
        (new Campaign())->approve($id, (int)(current_user()['id'] ?? 0));
        (new QueueJob())->create('campaign_process', ['campaign_id' => $id], $campaign['scheduled_at'] ?? null);
        audit_log('campaign.approved', 'campaign', $id);
        flash('success', 'Campaign approved and queued for processing.');
        redirect_url('index.php?route=messages/report&id=' . $id);
    }

    public function sendCampaignTest(): void
    {
        require_permission('messages.campaigns');
        verify_csrf();
        $campaignId = (int)($_POST['campaign_id'] ?? 0);
        $campaign = (new Campaign())->find($campaignId);
        if (!$campaign) {
            flash('error', 'Campaign not found.');
            redirect('messages/index');
        }
        $template = !empty($campaign['template_id']) ? (new Template())->find((int)$campaign['template_id']) : null;
        $variant = $_POST['variant'] ?? 'default';
        $sample = [
            'id' => 0,
            'first_name' => 'Avery',
            'last_name' => 'Jordan',
            'company' => 'Northwind Health',
            'email' => trim($_POST['to_address'] ?? ''),
            'phone' => trim($_POST['to_address'] ?? ''),
            'timezone' => config('app.timezone', 'America/Chicago'),
        ];
        try {
            if ($campaign['channel'] === 'sms') {
                $to = trim($_POST['to_address'] ?? '');
                $baseBody = $this->campaignBodyForVariant($campaign, $template, $variant);
                $body = apply_sms_preferences(render_template_content($baseBody, $sample), (int)($campaign['created_by'] ?? 0));
                $result = (new TwilioService())->sendSms($to, $body, null);
                $messageId = (new Message())->create([
                    'campaign_id' => $campaignId,
                    'channel' => 'sms',
                    'direction' => 'outbound',
                    'body' => $body,
                    'from_address' => effective_twilio_config((int)($campaign['created_by'] ?? 0))['from_number'],
                    'to_address' => $to,
                    'status' => $result['status'] ?? 'sent',
                    'external_id' => $result['sid'] ?? null,
                    'metadata_json' => json_encode(['mode' => 'test_send', 'variant' => $variant, 'provider' => $result]),
                ]);
            } else {
                $to = trim($_POST['to_address'] ?? '');
                $subjectBase = $this->campaignSubjectForVariant($campaign, $template, $variant);
                $bodyBase = $this->campaignBodyForVariant($campaign, $template, $variant);
                $subject = render_template_content($subjectBase ?: ($campaign['name'] ?? 'Campaign Test'), $sample);
                $body = apply_email_preferences(render_template_content($bodyBase, $sample), (int)($campaign['created_by'] ?? 0));
                $messageModel = new Message();
                $messageId = $messageModel->create([
                    'campaign_id' => $campaignId,
                    'channel' => 'email',
                    'direction' => 'outbound',
                    'subject' => $subject,
                    'body' => $body,
                    'from_address' => effective_mail_config((int)($campaign['created_by'] ?? 0))['from_email'],
                    'to_address' => $to,
                    'status' => 'queued',
                    'metadata_json' => json_encode(['mode' => 'test_send', 'variant' => $variant]),
                ]);
                $trackedHtml = instrument_email_html($body, $messageId);
                $externalId = '<msg-' . $messageId . '@' . parse_url(config('app.base_url'), PHP_URL_HOST) . '>';
                (new EmailService())->sendEmail($to, $subject, $trackedHtml, strip_tags($body), [], ['Message-ID: ' . $externalId]);
                $messageModel->updateExternalAndStatus($messageId, $externalId, 'sent', null);
            }
            audit_log('campaign.test_sent', 'campaign', $campaignId, ['to' => $_POST['to_address'] ?? '', 'variant' => $variant]);
            flash('success', 'Test send completed.');
        } catch (Throwable $e) {
            flash('error', $e->getMessage());
        }
        redirect_url('index.php?route=messages/report&id=' . $campaignId);
    }

    public function report(): void
    {
        require_permission('messages.campaigns');
        $id = (int)($_GET['id'] ?? 0);
        $campaignModel = new Campaign();
        $campaign = array_merge($campaignModel->find($id) ?: [], $campaignModel->summary($id) ?: []);
        if (!$campaign) {
            flash('error', 'Campaign not found.');
            redirect('messages/index');
        }
        $campaignHealth = [
            'delivery_rate' => round(((int)($campaign['delivered_count'] ?? 0) / max(1, (int)($campaign['total_recipients'] ?? 0))) * 100, 1),
            'bounce_rate' => round(((int)($campaign['bounced_count'] ?? 0) / max(1, (int)($campaign['total_recipients'] ?? 0))) * 100, 1),
            'open_rate' => round(((int)($campaign['unique_open_count'] ?? 0) / max(1, (int)($campaign['total_recipients'] ?? 0))) * 100, 1),
            'click_rate' => round(((int)($campaign['unique_click_count'] ?? 0) / max(1, (int)($campaign['total_recipients'] ?? 0))) * 100, 1),
        ];
        $this->view('messages/report', [
            'campaign' => $campaign,
            'campaignHealth' => $campaignHealth,
            'preflight' => (new CampaignService())->preflightForCampaign($campaign),
            'variantPerformance' => $campaignModel->variantPerformance($id),
            'providerStatus' => provider_status_summary(),
            'queueStats' => (new QueueJob())->stats(),
            'trend' => $campaignModel->messageTrend($id),
            'recipients' => $campaignModel->recipientBreakdown($id, 250),
            'comparison' => $campaignModel->compareRecent(8),
            'templatePerformance' => $campaignModel->templatePerformance(8),
            'segmentPerformance' => $campaignModel->segmentPerformance(8),
        ]);
    }

    private function campaignSubjectForVariant(array $campaign, ?array $template, string $variant): string
    {
        if ($variant === 'b' && !empty($campaign['variant_b_subject'])) {
            return (string)$campaign['variant_b_subject'];
        }
        if ($variant === 'a' && !empty($campaign['variant_a_subject'])) {
            return (string)$campaign['variant_a_subject'];
        }
        return (string)($campaign['subject_override'] ?? ($template['subject'] ?? $campaign['name'] ?? 'Campaign'));
    }

    private function campaignBaseBody(array $campaign, ?array $template): string
    {
        $body = trim((string)($campaign['body_override'] ?? ''));
        if ($body !== '') {
            return $body;
        }
        $blocks = json_decode((string)($campaign['builder_json'] ?? ''), true);
        if (is_array($blocks) && $blocks) {
            $html = [];
            foreach ($blocks as $block) {
                if (is_array($block) && !empty($block['html'])) {
                    $html[] = (string)$block['html'];
                }
            }
            if ($html) {
                return implode("

", $html);
            }
        }
        return (string)($template['body'] ?? '');
    }

    private function campaignBodyForVariant(array $campaign, ?array $template, string $variant): string
    {
        if ($variant === 'b' && !empty($campaign['variant_b_body'])) {
            return (string)$campaign['variant_b_body'];
        }
        if ($variant === 'a' && !empty($campaign['variant_a_body'])) {
            return (string)$campaign['variant_a_body'];
        }
        return $this->campaignBaseBody($campaign, $template);
    }


    private function buildDeliverabilityAlerts(array $healthSummary, array $queueStats, array $suppressionSummary, array $providerStatus): array
    {
        $alerts = [];
        if (empty($providerStatus['smtp']['configured'])) {
            $alerts[] = ['severity' => 'error', 'title' => 'SMTP not configured', 'detail' => 'Email campaigns cannot reliably send until SMTP or mail-from settings are completed.'];
        }
        if (empty($providerStatus['twilio']['configured'])) {
            $alerts[] = ['severity' => 'warn', 'title' => 'Twilio not configured', 'detail' => 'SMS campaigns and test sends will be blocked until Twilio credentials are added.'];
        }
        if ((float)($healthSummary['bounce_rate'] ?? 0) >= 3.0) {
            $alerts[] = ['severity' => 'warn', 'title' => 'Bounce rate elevated', 'detail' => 'Recent bounce rate is ' . number_format((float)$healthSummary['bounce_rate'], 1) . '%. Review imported lists and suppress stale addresses.'];
        }
        if ((int)($queueStats['failed_jobs'] ?? 0) > 0) {
            $alerts[] = ['severity' => 'error', 'title' => 'Queue failures need attention', 'detail' => (int)$queueStats['failed_jobs'] . ' queue jobs are currently failed and should be retried.'];
        }
        if ((int)($suppressionSummary['complaint_total'] ?? 0) > 0) {
            $alerts[] = ['severity' => 'warn', 'title' => 'Complaint suppressions present', 'detail' => (int)$suppressionSummary['complaint_total'] . ' addresses are suppressed due to complaints.'];
        }
        if (!$alerts) {
            $alerts[] = ['severity' => 'ok', 'title' => 'System health is stable', 'detail' => 'Providers, queue, and recent deliverability signals look healthy.'];
        }
        return $alerts;
    }

    public function exportCsv(): void
    {
        require_permission('messages.export');
        $filters = [
            'q' => trim($_GET['q'] ?? ''),
            'channel' => $_GET['channel'] ?? 'all',
            'direction' => $_GET['direction'] ?? 'all',
            'status' => $_GET['status'] ?? 'all',
        ];
        $rows = (new Message())->exportRows($filters);
        header('Content-Type: text/csv');
        header('Content-Disposition: attachment; filename="messages_export.csv"');
        $out = fopen('php://output', 'w');
        fputcsv($out, ['ID','Thread','Channel','Direction','Subject','Body','From','To','Status','Created At']);
        foreach ($rows as $row) {
            fputcsv($out, [$row['id'], $row['thread_key'], $row['channel'], $row['direction'], $row['subject'], strip_tags((string)$row['body']), $row['from_address'], $row['to_address'], $row['status'], $row['created_at']]);
        }
        fclose($out);
        exit;
    }

    public function saveConversationState(): void
    {
        require_permission('messages.reply');
        verify_csrf();
        (new ConversationState())->save($_POST);
        audit_log('conversation.state.updated', 'conversation', null, ['conversation_key' => $_POST['conversation_key'] ?? null, 'status' => $_POST['status'] ?? 'open']);
        flash('success', 'Conversation workflow updated.');
        redirect_url('index.php?route=messages/index&conversation=' . urlencode((string)($_POST['conversation_key'] ?? '')));
    }

    public function providerStatus(): void
    {
        require_permission('settings.view');
        $this->view('settings/provider_status', [
            'providerStatus' => provider_status_summary(),
            'testResults' => flash('provider_test_results') ?: [],
        ]);
    }

    public function unsubscribe(): void
    {
        $channel = $_GET['channel'] ?? 'email';
        $address = trim($_GET['address'] ?? '');
        if ($address) {
            (new Contact())->setUnsubscribed($channel, $address, true);
            (new Suppression())->add($channel, $address, 'unsubscribe');
        }
        echo '<!doctype html><html><head><meta charset="utf-8"><title>Unsubscribed</title><style>body{font-family:Arial,sans-serif;padding:40px;background:#f3f6fa;color:#1b2940}.card{max-width:640px;margin:50px auto;background:#fff;padding:32px;border-radius:14px;box-shadow:0 8px 30px rgba(0,0,0,.08)}</style></head><body><div class="card"><h1>Preference updated</h1><p>You have been unsubscribed from ' . e(strtoupper($channel)) . ' communications for <strong>' . e($address) . '</strong>.</p></div></body></html>';
        exit;
    }
}
