<?php

namespace FleekDash\Services;

use FleekDash\Models\Notifications;

class NotificationsService
{
    private static $instance = null;

    public static function getInstance()
    {
        if (null === self::$instance) {
            self::$instance = new self();
        }
        return self::$instance;
    }

    private function __construct()
    {
        // Capture notices, but only on admin pages
        if (is_admin()) {
            \add_action('admin_notices', [$this, 'startCapture'], -9999);
            \add_action('all_admin_notices', [$this, 'startCapture'], -9999);
            \add_action('admin_footer', [$this, 'processCapturedNotices'], 9999);

            // Hide the original notices to prevent double display
            \add_action('admin_print_styles', [$this, 'hideOriginalNotices']);
        }
    }

    public function startCapture()
    {
        ob_start();
    }

    public function hideOriginalNotices()
    {
        // Inline CSS hides default notice containers so we can render captured HTML once,
        // without unregistering hooks other plugins rely on.
        echo '<style>.notice, .updated, .error, .update-nag { display: none !important; }</style>';
    }

    public function processCapturedNotices()
    {
        $notices_html = ob_get_clean();
        if (empty($notices_html)) {
            return;
        }

        $doc = new \DOMDocument();
        @$doc->loadHTML('<?xml encoding="utf-8" ?>' . $notices_html);
        $divs = $doc->getElementsByTagName('div');

        foreach ($divs as $div) {
            $class = $div->getAttribute('class');
            if (strpos($class, 'notice') !== false || strpos($class, 'updated') !== false || strpos($class, 'error') !== false) {
                $message = trim($div->textContent);
                $html = $doc->saveHTML($div);

                if (empty($message)) {
                    continue;
                }

                $this->createOrUpdateNotificationFromHtml($message, $html, $class);
            }
        }
    }

    private function createOrUpdateNotificationFromHtml($message, $html, $class)
    {
        global $wpdb;

        $thread_id = 'wp_notice_' . md5(preg_replace('/[0-9\s]+/', '', $message)); // Group similar notices
        $type = $this->getNoticeType($class);
        $actions = $this->parseActions($html);

        $table = $wpdb->prefix . 'fleekdash_notifications';

        // Check if notification exists
        $existing = $wpdb->get_row($wpdb->prepare(
            "SELECT * FROM {$table} WHERE thread_id = %s AND status = 'unread' LIMIT 1",
            $thread_id
        ), ARRAY_A);

        $data = [
            'source' => 'wordpress',
            'type' => $type,
            'subject' => wp_trim_words($message, 10),
            'message' => $message,
            'actions' => json_encode($actions),
            'meta' => json_encode(['original_html' => $html, 'original_classes' => $class]),
            'status' => 'unread',
            'updated_at' => \current_time('mysql'),
        ];

        if ($existing) {
            // Update existing notification
            $wpdb->update(
                $table,
                $data,
                ['id' => $existing['id']],
                ['%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s'],
                ['%d']
            );
            return $existing['id'];
        } else {
            // Create new notification
            $data['thread_id'] = $thread_id;
            $data['created_at'] = \current_time('mysql');

            $wpdb->insert(
                $table,
                $data,
                ['%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s']
            );

            return $wpdb->insert_id;
        }
    }

    private function getNoticeType($classes)
    {
        $type = 'info';
        if (strpos($classes, 'notice-error') !== false || strpos($classes, 'error') !== false) {
            $type = 'error';
        } elseif (strpos($classes, 'notice-warning') !== false) {
            $type = 'warning';
        } elseif (strpos($classes, 'notice-info') !== false) {
            $type = 'info';
        } elseif (strpos($classes, 'notice-success') !== false || strpos($classes, 'updated') !== false) {
            $type = 'success';
        }
        return $type;
    }

    private function parseActions($html)
    {
        $actions = [];
        $doc = new \DOMDocument();
        @$doc->loadHTML('<?xml encoding="utf-8" ?>' . $html);
        $links = $doc->getElementsByTagName('a');

        foreach ($links as $link) {
            $href = $link->getAttribute('href');
            $text = $link->textContent;

            // Example: Detect plugin update links
            if (strpos($href, 'update.php?action=upgrade-plugin') !== false) {
                $actions[] = [
                    'type' => 'plugin_update',
                    'label' => $text,
                    'url' => $href,
                    'style' => 'primary',
                ];
            } else {
                // Generic link action
                $actions[] = [
                    'type' => 'link',
                    'label' => $text,
                    'url' => $href,
                    'style' => 'secondary',
                ];
            }
        }

        return $actions;
    }

    public function getThreads()
    {
        // This would be complex, involves grouping by thread_id,
        // getting the latest message per thread, counts, etc.
        // For now, let's just get visible notifications.
        return Notifications::getVisible();
    }

    public function cleanUp()
    {
        global $wpdb;

        $table = $wpdb->prefix . 'fleekdash_notifications';
        $thirty_days_ago = date('Y-m-d H:i:s', strtotime('-30 days'));
        $now = \current_time('mysql');

        // Delete old resolved notices
        $wpdb->query($wpdb->prepare(
            "DELETE FROM {$table} WHERE status = 'resolved' AND resolved_at < %s",
            $thirty_days_ago
        ));

        // Un-snooze notices whose time has come
        $wpdb->update(
            $table,
            [
                'status' => 'unread',
                'snoozed_until' => null
            ],
            [
                'status' => 'snoozed'
            ],
            ['%s', '%s'],
            ['%s']
        );

        // Additional WHERE clause for snoozed_until
        $wpdb->query($wpdb->prepare(
            "UPDATE {$table}
             SET status = 'unread', snoozed_until = NULL
             WHERE status = 'snoozed' AND snoozed_until <= %s",
            $now
        ));
    }
}
