<?php

if (!defined('ABSPATH')) {
    exit;
}

class WNC_Quality_Dashboard {

    private static $rows = null;

    public static function init() {
        add_action('admin_post_wnc_export_quality', [__CLASS__, 'export_csv']);
    }

    public static function get_rows() {
        if (is_array(self::$rows)) {
            return self::$rows;
        }

        self::$rows = [];
        $post_types = function_exists('wnc_get_enabled_post_types')
            ? wnc_get_enabled_post_types()
            : ['post', 'page'];

        if (empty($post_types) || !class_exists('WNC_Connect_Tags') || !class_exists('WNC_Connect_Health')) {
            return self::$rows;
        }

        $post_ids = get_posts([
            'post_type'      => $post_types,
            'post_status'    => ['publish', 'draft', 'private'],
            'posts_per_page' => -1,
            'fields'         => 'ids',
            'orderby'        => 'title',
            'order'          => 'ASC',
        ]);

        foreach ($post_ids as $post_id) {
            $data = WNC_Connect_Tags::get_data($post_id);
            $checks = WNC_Connect_Health::checks($data, $post_id);
            $score = WNC_Connect_Health::score($checks);
            $missing = [];
            $missing_keys = [];

            foreach ($checks as $check) {
                if (empty($check['ok'])) {
                    $missing[] = $check['label'];
                    $missing_keys[] = $check['key'];
                }
            }

            $post_type = get_post_type($post_id);
            $is_event = function_exists('wnc_is_event_post_type')
                ? wnc_is_event_post_type($post_type)
                : strtolower(trim((string) ($data['placeMode'] ?? ''))) === 'event';
            $post_type_object = get_post_type_object($post_type);

            self::$rows[] = [
                'id'            => $post_id,
                'title'         => get_the_title($post_id),
                'post_type'     => $post_type,
                'post_type_label' => $post_type_object->labels->singular_name ?? $post_type,
                'mode'          => $is_event ? 'event' : 'place',
                'status'        => get_post_status($post_id),
                'score'         => $score,
                'missing'       => $missing,
                'missing_keys'  => $missing_keys,
                'modified'      => get_post_modified_time('Y-m-d H:i', false, $post_id),
            ];
        }

        usort(self::$rows, function ($a, $b) {
            if ($a['score'] === $b['score']) {
                return strcasecmp($a['title'], $b['title']);
            }

            return $a['score'] <=> $b['score'];
        });

        return self::$rows;
    }

    private static function filters() {
        $allowed_per_page = [25, 50, 100];
        $per_page = isset($_GET['wnc_per_page']) ? absint($_GET['wnc_per_page']) : 25;

        return [
            'search'    => isset($_GET['wnc_search']) ? sanitize_text_field(wp_unslash($_GET['wnc_search'])) : '',
            'post_type' => isset($_GET['wnc_post_type']) ? sanitize_key(wp_unslash($_GET['wnc_post_type'])) : '',
            'mode'      => isset($_GET['wnc_mode']) ? sanitize_key(wp_unslash($_GET['wnc_mode'])) : '',
            'missing'   => isset($_GET['wnc_missing']) ? sanitize_key(wp_unslash($_GET['wnc_missing'])) : '',
            'per_page'  => in_array($per_page, $allowed_per_page, true) ? $per_page : 25,
            'page'      => max(1, isset($_GET['wnc_page']) ? absint($_GET['wnc_page']) : 1),
        ];
    }

    private static function filter_rows($rows, $filters) {
        return array_values(array_filter($rows, function ($row) use ($filters) {
            if ($filters['search'] !== '' && stripos($row['title'], $filters['search']) === false) {
                return false;
            }

            if ($filters['post_type'] !== '' && $row['post_type'] !== $filters['post_type']) {
                return false;
            }

            if ($filters['mode'] !== '' && $row['mode'] !== $filters['mode']) {
                return false;
            }

            if ($filters['missing'] !== '' && !in_array($filters['missing'], $row['missing_keys'], true)) {
                return false;
            }

            return true;
        }));
    }

    private static function summary($rows) {
        $total = count($rows);
        $score_total = 0;
        $ready = 0;
        $events = 0;

        foreach ($rows as $row) {
            $score_total += $row['score'];
            $ready += $row['score'] >= 85 ? 1 : 0;
            $events += $row['mode'] === 'event' ? 1 : 0;
        }

        return [
            'total' => $total,
            'ready' => $ready,
            'needs_work' => max(0, $total - $ready),
            'average' => $total > 0 ? (int) round($score_total / $total) : 0,
            'events' => $events,
            'places' => max(0, $total - $events),
        ];
    }

    private static function missing_options($rows) {
        $options = [];

        foreach ($rows as $row) {
            foreach ($row['missing_keys'] as $index => $key) {
                $label = $row['missing'][$index] ?? $key;

                if (!isset($options[$key])) {
                    $options[$key] = ['label' => $label, 'count' => 0];
                }

                $options[$key]['count']++;
            }
        }

        uasort($options, function ($a, $b) {
            return strcasecmp($a['label'], $b['label']);
        });

        return $options;
    }

    private static function mapping_warnings() {
        $options = wnc_get_options();
        $enabled = wnc_get_enabled_post_types();
        $events = function_exists('wnc_get_event_post_types') ? wnc_get_event_post_types() : [];
        $warnings = [];

        if (empty($enabled)) {
            $warnings[] = 'No post types are enabled. Select at least one under Where Next Settings.';
        }

        if (!empty($events) && empty($options['event_start_date_key'])) {
            $warnings[] = 'Event post types are enabled, but Event Start Date has no default field mapping.';
        }

        if (!empty($events) && empty($options['event_end_date_key'])) {
            $warnings[] = 'Event post types are enabled, but Event End Date has no default field mapping.';
        }

        $place_types = array_diff($enabled, $events);
        $location_mappings = [
            $options['address_key'] ?? '',
            $options['postcode_key'] ?? '',
            $options['what3words_key'] ?? '',
            $options['latitude_key'] ?? '',
            $options['longitude_key'] ?? '',
        ];

        if (!empty($place_types) && !array_filter($location_mappings)) {
            $warnings[] = 'Place content has no default address, postcode, coordinates or what3words mapping.';
        }

        return $warnings;
    }

    public static function render_page() {
        if (!current_user_can('manage_options')) {
            return;
        }

        $all_rows = self::get_rows();
        $filters = self::filters();
        $filtered_rows = self::filter_rows($all_rows, $filters);
        $summary = self::summary($all_rows);
        $missing_options = self::missing_options($all_rows);
        $total_pages = max(1, (int) ceil(count($filtered_rows) / $filters['per_page']));
        $filters['page'] = min($filters['page'], $total_pages);
        $page_rows = array_slice(
            $filtered_rows,
            ($filters['page'] - 1) * $filters['per_page'],
            $filters['per_page']
        );
        $enabled_post_types = wnc_get_enabled_post_types();
        $export_url = wp_nonce_url(
            add_query_arg(
                array_filter([
                    'action' => 'wnc_export_quality',
                    'wnc_search' => $filters['search'],
                    'wnc_post_type' => $filters['post_type'],
                    'wnc_mode' => $filters['mode'],
                    'wnc_missing' => $filters['missing'],
                ]),
                admin_url('admin-post.php')
            ),
            'wnc_export_quality'
        );
        ?>
        <div class="wrap wnc-quality-wrap">
            <h1>Where Next Content Quality</h1>
            <p>Compatibility and missing-field checks across every enabled post type. Scores use different relevant fields for places and events.</p>

            <?php foreach (self::mapping_warnings() as $warning) : ?>
                <div class="notice notice-warning inline"><p><?php echo esc_html($warning); ?> <a href="<?php echo esc_url(admin_url('admin.php?page=where-next')); ?>">Review settings</a></p></div>
            <?php endforeach; ?>

            <div class="wnc-quality-cards">
                <?php self::render_card('Total Content', $summary['total']); ?>
                <?php self::render_card('Ready (85%+)', $summary['ready'], 'good'); ?>
                <?php self::render_card('Needs Work', $summary['needs_work'], $summary['needs_work'] ? 'warning' : 'good'); ?>
                <?php self::render_card('Average Score', $summary['average'] . '%', $summary['average'] >= 85 ? 'good' : 'warning'); ?>
                <?php self::render_card('Places', $summary['places']); ?>
                <?php self::render_card('Events', $summary['events']); ?>
            </div>

            <form method="get" class="wnc-quality-filters">
                <input type="hidden" name="page" value="where-next-quality">
                <label>Name<input type="search" name="wnc_search" value="<?php echo esc_attr($filters['search']); ?>" placeholder="Search titles"></label>
                <label>Post type<select name="wnc_post_type"><option value="">All post types</option>
                    <?php foreach ($enabled_post_types as $post_type) : $object = get_post_type_object($post_type); ?>
                        <option value="<?php echo esc_attr($post_type); ?>" <?php selected($filters['post_type'], $post_type); ?>><?php echo esc_html($object->labels->name ?? $post_type); ?></option>
                    <?php endforeach; ?>
                </select></label>
                <label>Content type<select name="wnc_mode"><option value="">Places and events</option><option value="place" <?php selected($filters['mode'], 'place'); ?>>Places</option><option value="event" <?php selected($filters['mode'], 'event'); ?>>Events</option></select></label>
                <label>Missing field<select name="wnc_missing"><option value="">Any field</option>
                    <?php foreach ($missing_options as $key => $item) : ?>
                        <option value="<?php echo esc_attr($key); ?>" <?php selected($filters['missing'], $key); ?>><?php echo esc_html($item['label'] . ' (' . $item['count'] . ')'); ?></option>
                    <?php endforeach; ?>
                </select></label>
                <label>Rows<select name="wnc_per_page"><?php foreach ([25, 50, 100] as $size) : ?><option value="<?php echo esc_attr($size); ?>" <?php selected($filters['per_page'], $size); ?>><?php echo esc_html($size); ?></option><?php endforeach; ?></select></label>
                <?php submit_button('Filter', 'primary', '', false); ?>
                <a class="button" href="<?php echo esc_url(admin_url('admin.php?page=where-next-quality')); ?>">Reset</a>
                <a class="button" href="<?php echo esc_url($export_url); ?>">Export CSV</a>
                <span class="wnc-quality-count"><?php echo esc_html(count($filtered_rows) . ' matching of ' . count($all_rows)); ?></span>
            </form>

            <?php self::render_table($page_rows); ?>
            <?php self::render_pagination($filters, $total_pages); ?>
        </div>
        <style>
            .wnc-quality-cards{display:flex;gap:14px;flex-wrap:wrap;margin:20px 0}.wnc-quality-card{background:#fff;border:1px solid #c3c4c7;border-radius:10px;padding:16px 18px;min-width:150px}.wnc-quality-card.good{border-color:#16a34a;background:#f0fdf4}.wnc-quality-card.warning{border-color:#f59e0b;background:#fffbeb}.wnc-quality-card strong{display:block;font-size:27px;line-height:1.1;margin-bottom:5px}.wnc-quality-filters{display:flex;gap:10px;align-items:end;flex-wrap:wrap;background:#fff;border:1px solid #c3c4c7;padding:14px;margin:18px 0}.wnc-quality-filters label{display:flex;flex-direction:column;gap:4px;font-weight:600}.wnc-quality-filters select,.wnc-quality-filters input{min-height:34px}.wnc-quality-count{margin-left:auto;padding:8px}.wnc-score{font-weight:800}.wnc-score-good{color:#15803d}.wnc-score-mid{color:#b45309}.wnc-score-low{color:#b91c1c}.wnc-quality-pagination{display:flex;justify-content:flex-end;gap:5px;margin-top:14px}.wnc-quality-pagination .button.current{background:#2271b1;color:#fff;border-color:#2271b1}@media(max-width:782px){.wnc-quality-count{margin-left:0;width:100%}.wnc-quality-wrap table{display:block;overflow-x:auto}}
        </style>
        <?php
    }

    private static function render_card($label, $value, $class = '') {
        echo '<div class="wnc-quality-card ' . esc_attr($class) . '"><strong>' . esc_html($value) . '</strong><span>' . esc_html($label) . '</span></div>';
    }

    private static function render_table($rows) {
        if (empty($rows)) {
            echo '<p>No matching content found.</p>';
            return;
        }

        echo '<table class="widefat striped"><thead><tr><th>Title</th><th>Post type</th><th>Content type</th><th>Status</th><th>Score</th><th>Missing fields</th><th>Updated</th><th>Actions</th></tr></thead><tbody>';

        foreach ($rows as $row) {
            $score_class = $row['score'] >= 85 ? 'wnc-score-good' : ($row['score'] >= 65 ? 'wnc-score-mid' : 'wnc-score-low');
            echo '<tr>';
            echo '<td><strong>' . esc_html($row['title']) . '</strong><br><code>#' . esc_html($row['id']) . '</code></td>';
            echo '<td>' . esc_html($row['post_type_label']) . '<br><code>' . esc_html($row['post_type']) . '</code></td>';
            echo '<td>' . esc_html(ucfirst($row['mode'])) . '</td>';
            echo '<td>' . esc_html($row['status']) . '</td>';
            echo '<td><span class="wnc-score ' . esc_attr($score_class) . '">' . esc_html($row['score']) . '%</span></td>';
            echo '<td>' . esc_html($row['missing'] ? implode(', ', $row['missing']) : '—') . '</td>';
            echo '<td>' . esc_html($row['modified']) . '</td>';
            echo '<td><a href="' . esc_url(get_edit_post_link($row['id'])) . '">Edit</a> | <a href="' . esc_url(get_permalink($row['id'])) . '" target="_blank" rel="noopener">View</a></td>';
            echo '</tr>';
        }

        echo '</tbody></table>';
    }

    private static function render_pagination($filters, $total_pages) {
        if ($total_pages <= 1) {
            return;
        }

        echo '<div class="wnc-quality-pagination">';

        for ($page = 1; $page <= $total_pages; $page++) {
            $url = add_query_arg([
                'page' => 'where-next-quality',
                'wnc_search' => $filters['search'],
                'wnc_post_type' => $filters['post_type'],
                'wnc_mode' => $filters['mode'],
                'wnc_missing' => $filters['missing'],
                'wnc_per_page' => $filters['per_page'],
                'wnc_page' => $page,
            ], admin_url('admin.php'));
            $class = $page === $filters['page'] ? 'button current' : 'button';
            echo '<a class="' . esc_attr($class) . '" href="' . esc_url($url) . '">' . esc_html($page) . '</a>';
        }

        echo '</div>';
    }

    public static function export_csv() {
        if (!current_user_can('manage_options')) {
            wp_die('You do not have permission to export this report.');
        }

        check_admin_referer('wnc_export_quality');
        $rows = self::filter_rows(self::get_rows(), self::filters());
        nocache_headers();
        header('Content-Type: text/csv; charset=utf-8');
        header('Content-Disposition: attachment; filename=where-next-content-quality-' . gmdate('Y-m-d') . '.csv');
        $output = fopen('php://output', 'w');
        fputcsv($output, ['ID', 'Title', 'Post Type', 'Content Type', 'Status', 'Score', 'Missing Fields', 'Updated', 'URL'], ',', '"', '');

        foreach ($rows as $row) {
            fputcsv($output, [
                $row['id'],
                $row['title'],
                $row['post_type'],
                $row['mode'],
                $row['status'],
                $row['score'],
                implode(', ', $row['missing']),
                $row['modified'],
                get_permalink($row['id']),
            ], ',', '"', '');
        }

        fclose($output);
        exit;
    }
}
