<?php
defined('ABSPATH') or die('Direct access not allowed');

/**
 * VollstartRD_Notifications — Email notification system.
 *
 * SRP: Sends emails for status changes, new messages, new repairs, pickup reminders.
 * Handles placeholder replacement and WP Cron for pickup reminders.
 * No business logic here — only email composition and sending.
 */
class VollstartRD_Notifications {

    private $MAIN;

    public function __construct($MAIN) {
        $this->MAIN = $MAIN;

        // WP Cron for pickup reminders
        add_action('vollstart_rd_pickup_reminder_cron', [$this, 'processPickupReminders']);
    }

    /**
     * Schedule the pickup reminder cron event (daily).
     * Called from main plugin init.
     */
    public function schedulePickupReminder(): void {
        if (!wp_next_scheduled('vollstart_rd_pickup_reminder_cron')) {
            wp_schedule_event(time(), 'daily', 'vollstart_rd_pickup_reminder_cron');
        }
    }

    /**
     * Unschedule the pickup reminder cron event.
     * Called on plugin deactivation.
     */
    public static function unschedulePickupReminder(): void {
        $timestamp = wp_next_scheduled('vollstart_rd_pickup_reminder_cron');
        if ($timestamp) {
            wp_unschedule_event($timestamp, 'vollstart_rd_pickup_reminder_cron');
        }
    }

    // --- Public send methods ---

    /**
     * Send email to customer when repair status changes (F13).
     */
    public function sendStatusChangeEmail(int $repairId, string $newStatus): void {
        $opts = $this->MAIN->getOptions();
        if (!$opts->isCheckboxActive('emailStatusChangeEnabled')) {
            return;
        }

        // Check status filter (comma-separated list, empty = all)
        $allowedStatuses = $opts->getOptionValue('emailStatusChangeStatuses');
        if (!empty($allowedStatuses)) {
            $allowed = array_map('trim', explode(',', $allowedStatuses));
            if (!in_array($newStatus, $allowed)) {
                return;
            }
        }

        $repair = $this->MAIN->getRepairs()->getById($repairId);
        if (!$repair) {
            return;
        }

        $customer = $this->getCustomerForRepair($repair);
        if (!$customer || empty($customer['email'])) {
            return;
        }

        $statusLabel = $this->MAIN->getRepairs()->getStatusLabel($newStatus);

        // Subject
        $subjectTemplate = $opts->getOptionValue('emailStatusChangeSubject')
            ?: __('Repair Update: {repair_number} — {status}', 'vollstart-repair-desk');
        $subject = $this->replacePlaceholders($subjectTemplate, $repair, $customer, $statusLabel);

        // Body — read from Free option; falls back to built-in default template.
        $bodyTemplate = $this->MAIN->getOptions()->getOptionValue('emailStatusChangeBody') ?: $this->getDefaultStatusChangeBody();
        $body = $this->replacePlaceholders($bodyTemplate, $repair, $customer, $statusLabel);

        $this->sendHtmlEmail($customer['email'], $subject, $body, $repairId, 'status_change');
    }

    /**
     * Send email to customer when workshop sends a message.
     */
    public function sendCustomerMessageEmail(int $repairId, string $message): void {
        $opts = $this->MAIN->getOptions();
        if (!$opts->isCheckboxActive('emailCustomerMessageEnabled')) {
            return;
        }

        $repair = $this->MAIN->getRepairs()->getById($repairId);
        if (!$repair) return;

        $customer = $this->getCustomerForRepair($repair);
        if (!$customer || empty($customer['email'])) return;

        $subjectTemplate = $opts->getOptionValue('emailCustomerMessageSubject')
            ?: __('Message from {business_name} — {repair_number}', 'vollstart-repair-desk');
        $subject = $this->replacePlaceholders($subjectTemplate, $repair, $customer, '', $message);

        $bodyTemplate = $this->MAIN->getOptions()->getOptionValue('emailCustomerMessageBody') ?: $this->getDefaultCustomerMessageBody();
        $body = $this->replacePlaceholders($bodyTemplate, $repair, $customer, '', esc_html($message));

        $this->sendHtmlEmail($customer['email'], $subject, $body, $repairId, 'customer_message');
    }

    /**
     * Send email to business when customer sends a message (F14).
     */
    public function sendNewMessageNotification(int $repairId, string $message): void {
        $opts = $this->MAIN->getOptions();
        if (!$opts->isCheckboxActive('emailNewMessageEnabled')) {
            return;
        }

        $repair = $this->MAIN->getRepairs()->getById($repairId);
        if (!$repair) return;

        $customer = $this->getCustomerForRepair($repair);
        $to = $this->getBusinessEmail();

        $subjectTemplate = $opts->getOptionValue('emailNewMessageSubject')
            ?: __('New customer message on repair {repair_number}', 'vollstart-repair-desk');
        $subject = $this->replacePlaceholders($subjectTemplate, $repair, $customer, '', $message);

        $bodyTemplate = $this->MAIN->getOptions()->getOptionValue('emailNewMessageBody') ?: $this->getDefaultNewMessageBody();
        $body = $this->replacePlaceholders($bodyTemplate, $repair, $customer, '', mb_substr(wp_strip_all_tags($message), 0, 500));

        $this->sendHtmlEmail($to, $subject, $body, $repairId, 'new_message');
    }

    /**
     * Send email to business when a new repair is created.
     */
    public function sendNewRepairNotification(int $repairId): void {
        $opts = $this->MAIN->getOptions();
        if (!$opts->isCheckboxActive('emailNotifyAdmin')) {
            return;
        }

        $repair = $this->MAIN->getRepairs()->getById($repairId);
        if (!$repair) {
            return;
        }

        $to = $this->getBusinessEmail();
        $customer = $this->getCustomerForRepair($repair);

        $subjectTemplate = $opts->getOptionValue('emailNewRepairSubject')
            ?: __('New repair created: {repair_number}', 'vollstart-repair-desk');
        $subject = $this->replacePlaceholders($subjectTemplate, $repair, $customer);

        $bodyTemplate = $this->MAIN->getOptions()->getOptionValue('emailNewRepairBody') ?: $this->getDefaultNewRepairBody();
        $body = $this->replacePlaceholders($bodyTemplate, $repair, $customer);

        $this->sendHtmlEmail($to, $subject, $body, $repairId, 'new_repair');
    }

    /**
     * Send pickup reminder to customer (F15).
     */
    public function sendPickupReminder(int $repairId): void {
        $opts = $this->MAIN->getOptions();
        if (!$opts->isCheckboxActive('pickupReminderEnabled')) {
            return;
        }

        $repair = $this->MAIN->getRepairs()->getById($repairId);
        if (!$repair) {
            return;
        }

        $customer = $this->getCustomerForRepair($repair);
        if (!$customer || empty($customer['email'])) {
            return;
        }

        $opts = $this->MAIN->getOptions();

        $subjectTemplate = $opts->getOptionValue('pickupReminderSubject')
            ?: __('Reminder: Your repair {repair_number} is ready for pickup', 'vollstart-repair-desk');
        $subject = $this->replacePlaceholders($subjectTemplate, $repair, $customer);

        $bodyTemplate = $this->MAIN->getOptions()->getOptionValue('pickupReminderBody') ?: $this->getDefaultPickupReminderBody();
        $body = $this->replacePlaceholders($bodyTemplate, $repair, $customer);

        $sent = $this->sendHtmlEmail($customer['email'], $subject, $body, $repairId, 'pickup_reminder');

        // Mark reminder as sent regardless of send success (to avoid spamming)
        if ($sent) {
            $this->MAIN->getDB()->update('repairs', [
                'pickup_reminder_sent' => 1,
            ], ['id' => $repairId]);
        }
    }

    // --- WP Cron callback ---

    /**
     * Process pickup reminders. Called daily by WP Cron.
     * Finds repairs in 'done' status for X days without reminder sent.
     */
    public function processPickupReminders(): void {
        $opts = $this->MAIN->getOptions();
        if (!$opts->isCheckboxActive('pickupReminderEnabled')) {
            return;
        }

        $days = max(1, (int) ($opts->getOptionValue('pickupReminderDays') ?: 3));
        $db = $this->MAIN->getDB();
        $repairsTbl = $db->getTabelle('repairs');
        $statusLogTbl = $db->getTabelle('status_log');

        // Find repairs that:
        // 1. Are currently in 'done' status
        // 2. Have NOT had a pickup reminder sent
        // 3. Reached 'done' status at least X days ago
        $cutoff = wp_date('Y-m-d H:i:s', strtotime("-{$days} days"));

        $repairs = $db->getResults(
            "SELECT r.id FROM %i r
             INNER JOIN %i sl ON sl.repair_id = r.id
                AND sl.event_type = 'status_change'
                AND sl.new_status = 'done'
             WHERE r.status = 'done'
               AND r.pickup_reminder_sent = 0
               AND sl.created_at <= %s
             GROUP BY r.id",
            $repairsTbl,
            $statusLogTbl,
            $cutoff
        );

        foreach ($repairs as $row) {
            $this->sendPickupReminder((int) $row['id']);
        }
    }

    // --- Helper methods ---

    /**
     * Get business email from option or fallback to admin email.
     */
    public function getBusinessEmail(): string {
        $email = $this->MAIN->getOptions()->getOptionValue('businessEmail');
        return !empty($email) ? $email : get_option('admin_email');
    }

    /**
     * Get business name from option or fallback to blog name.
     */
    public function getBusinessName(): string {
        $name = $this->MAIN->getOptions()->getOptionValue('businessName');
        return !empty($name) ? $name : get_bloginfo('name');
    }

    /**
     * Get business phone from option (empty when not set).
     */
    public function getBusinessPhone(): string {
        return (string) ($this->MAIN->getOptions()->getOptionValue('businessPhone') ?: '');
    }

    /**
     * Get customer record for a repair.
     */
    public function getCustomerForRepair(array $repair): ?array {
        if (empty($repair['customer_id'])) {
            return null;
        }
        return $this->MAIN->getCustomers()->getById((int) $repair['customer_id']);
    }

    /**
     * Replace all placeholders in a template string.
     */
    public function replacePlaceholders(string $template, array $repair, ?array $customer = null, string $statusLabel = '', string $message = ''): string {
        $device = trim(($repair['device_brand'] ?? '') . ' ' . ($repair['device_model'] ?? ''));
        $statusUrl = $this->MAIN->getFrontend()->getStatusUrl($repair);

        $replacements = [
            '{customer_name}'  => $customer['name'] ?? '',
            '{repair_number}'  => $repair['repair_number'] ?? '',
            '{device}'         => $device,
            '{status}'         => $statusLabel ?: $this->MAIN->getRepairs()->getStatusLabel($repair['status']),
            '{estimated_date}' => $repair['estimated_date'] ?: __('Not set', 'vollstart-repair-desk'),
            '{business_name}'  => $this->getBusinessName(),
            '{business_email}' => $this->getBusinessEmail(),
            '{business_phone}' => $this->MAIN->getOptions()->getOptionValue('businessPhone') ?: '',
            '{status_url}'     => $statusUrl,
            '{admin_url}'      => esc_url(admin_url('admin.php?page=vollstart-repair-desk')),
            '{message}'        => esc_html($message),
        ];

        return str_replace(array_keys($replacements), array_values($replacements), $template);
    }

    /**
     * Default status change email body (used when option is empty).
     */
    private function getDefaultNewRepairBody(): string {
        return __("<p>A new repair <strong>{repair_number}</strong> has been created.</p>\n<p><strong>Device:</strong> {device}<br>\n<strong>Customer:</strong> {customer_name}</p>\n<p><a href=\"{admin_url}\">Open Repair Desk</a></p>\n<p>{business_name}</p>", 'vollstart-repair-desk');
    }

    private function getDefaultCustomerMessageBody(): string {
        return __("<p>Hi {customer_name},</p>\n<p>You have a new message regarding your repair <strong>{repair_number}</strong>:</p>\n<blockquote style=\"border-left:3px solid #f97316;padding:8px 16px;margin:16px 0;color:#1e293b\">{message}</blockquote>\n<p>You can view details and reply here:<br>\n<a href=\"{status_url}\">{status_url}</a></p>\n<p>Or simply reply to this email.</p>\n<p>Best regards,<br>\n{business_name}</p>", 'vollstart-repair-desk');
    }

    private function getDefaultNewMessageBody(): string {
        return __("<p>A customer has sent a new message on repair <strong>{repair_number}</strong>:</p>\n<blockquote style=\"border-left:3px solid #e2e8f0;padding:8px 16px;margin:16px 0;color:#475569\">{message}</blockquote>\n<p><a href=\"{admin_url}\">Open Repair Desk</a> to reply.</p>\n<p>{business_name}</p>", 'vollstart-repair-desk');
    }

    private function getDefaultPickupReminderBody(): string {
        return __("<p>Hi {customer_name},</p>\n<p>This is a friendly reminder that your repair <strong>{repair_number}</strong> ({device}) is ready for pickup.</p>\n<p>You can check the details here:<br>\n<a href=\"{status_url}\">{status_url}</a></p>\n<p>Best regards,<br>\n{business_name}</p>", 'vollstart-repair-desk');
    }

    private function getDefaultStatusChangeBody(): string {
        return __("<p>Hi {customer_name},</p>\n<p>Your repair <strong>{repair_number}</strong> has been updated.</p>\n<p><strong>Device:</strong> {device}<br>\n<strong>New status:</strong> {status}<br>\n<strong>Estimated completion:</strong> {estimated_date}</p>\n<p>You can check the current status anytime here:<br>\n<a href=\"{status_url}\">{status_url}</a></p>\n<p>Best regards,<br>\n{business_name}</p>", 'vollstart-repair-desk');
    }

    /**
     * Send an HTML email via wp_mail.
     */
    public function sendHtmlEmail(string $to, string $subject, string $body, int $repairId = 0, string $emailType = ''): bool {
        $headers = ['Content-Type: text/html; charset=UTF-8'];

        $fromName = $this->getBusinessName();
        $fromEmail = $this->getBusinessEmail();
        if ($fromEmail) {
            $headers[] = 'From: ' . $fromName . ' <' . $fromEmail . '>';
            $headers[] = 'Reply-To: ' . $fromName . ' <' . $fromEmail . '>';
        }

        $result = wp_mail($to, $subject, $body, $headers);

        // Log email
        $this->logEmail($repairId, $emailType, $to, $subject, $body, $result);

        return $result;
    }

    public function logEmail(int $repairId, string $emailType, string $recipient, string $subject, string $body, bool $success): void {
        $user = wp_get_current_user();
        $this->MAIN->getDB()->insert('email_logs', [
            'repair_id'  => $repairId,
            'email_type' => $emailType,
            'recipient'  => $recipient,
            'subject'    => $subject,
            'body'       => $body,
            'success'    => $success ? 1 : 0,
            'sent_by'    => $user && $user->ID ? $user->display_name : 'System',
            'created_at' => current_time('mysql'),
        ]);
    }

    /**
     * Get email history for a repair.
     */
    public function getEmailLog(int $repairId): array {
        $db = $this->MAIN->getDB();
        $tbl = $db->getTabelle('email_logs');
        return $db->getResults("SELECT * FROM %i WHERE repair_id = %d ORDER BY created_at DESC", $tbl, $repairId);
    }

    /**
     * Get all emails sent to a customer (across repairs).
     */
    public function getEmailLogForCustomer(int $customerId): array {
        $db = $this->MAIN->getDB();
        $tbl = $db->getTabelle('email_logs');
        $rtbl = $db->getTabelle('repairs');
        return $db->getResults(
            "SELECT e.*, r.repair_number FROM %i e INNER JOIN %i r ON e.repair_id = r.id WHERE r.customer_id = %d ORDER BY e.created_at DESC LIMIT 50",
            $tbl, $rtbl, $customerId
        );
    }

    /**
     * Resend an email from log (uses current customer email).
     */
    public function resendEmail(int $logId): bool {
        $db = $this->MAIN->getDB();
        $tbl = $db->getTabelle('email_logs');
        $log = $db->getRow("SELECT * FROM %i WHERE id = %d", $tbl, $logId);
        if (!$log) return false;

        // Get current customer email (may have been corrected)
        $recipient = $log['recipient'];
        if ($log['repair_id']) {
            $repair = $this->MAIN->getRepairs()->getById((int) $log['repair_id']);
            if ($repair) {
                $customer = $this->getCustomerForRepair($repair);
                if ($customer && !empty($customer['email'])) {
                    $recipient = $customer['email'];
                }
            }
        }

        return $this->sendHtmlEmail($recipient, $log['subject'], $log['body'], (int) $log['repair_id'], 'resend_' . $log['email_type']);
    }

    /**
     * Manually send a status/pickup email for a repair (works even if auto-emails are off).
     */
    public function sendManualEmail(int $repairId): bool {
        $repair = $this->MAIN->getRepairs()->getById($repairId);
        if (!$repair) return false;

        $customer = $this->getCustomerForRepair($repair);
        if (!$customer || empty($customer['email'])) return false;

        $statusLabel = $this->MAIN->getRepairs()->getStatusLabel($repair['status']);
        $subjectTemplate = $this->MAIN->getOptions()->getOptionValue('emailStatusChangeSubject')
            ?: __('Repair Update: {repair_number} — {status}', 'vollstart-repair-desk');
        $subject = $this->replacePlaceholders($subjectTemplate, $repair, $customer, $statusLabel);

        $bodyTemplate = $this->MAIN->getOptions()->getOptionValue('emailStatusChangeBody') ?: $this->getDefaultStatusChangeBody();
        $body = $this->replacePlaceholders($bodyTemplate, $repair, $customer, $statusLabel);

        return $this->sendHtmlEmail($customer['email'], $subject, $body, $repairId, 'manual_status');
    }
}
