<?php
/**
 * Public events calendar: tournaments with dates from Chess Podium (past, current & upcoming).
 *
 * @package Chess_Podium
 */

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

final class ChessPodium_Events_Calendar
{
    /**
     * Normalize a date string to Y-m-d or null.
     */
    public static function normalize_date_string($value): ?string
    {
        if ($value === null) {
            return null;
        }
        $s = trim((string) $value);
        if ($s === '' || $s === '0000-00-00') {
            return null;
        }
        if (!preg_match('/^\d{4}-\d{2}-\d{2}$/', $s)) {
            return null;
        }
        $ts = strtotime($s . ' 12:00:00');
        if ($ts === false) {
            return null;
        }
        return gmdate('Y-m-d', $ts);
    }

    /**
     * Effective start: tournament row, brochure meta, or first round date.
     */
    public static function effective_start_date(?object $tournament): ?string
    {
        if (!$tournament) {
            return null;
        }
        $row = self::normalize_date_string($tournament->start_date ?? null);
        if ($row !== null) {
            return $row;
        }
        $tid = (int) ($tournament->id ?? 0);
        if ($tid <= 0 || !class_exists('ChessPodium_PdfBrochure')) {
            return null;
        }
        $bro = ChessPodium_PdfBrochure::get_meta($tid, 'start_date');
        $n = self::normalize_date_string($bro);
        if ($n !== null) {
            return $n;
        }
        $rd = ChessPodium_PdfBrochure::get_meta($tid, 'round_dates');
        if ($rd) {
            $arr = json_decode($rd, true);
            if (is_array($arr)) {
                ksort($arr, SORT_NUMERIC);
                foreach ($arr as $d) {
                    $x = self::normalize_date_string($d);
                    if ($x !== null) {
                        return $x;
                    }
                }
            }
        }
        return null;
    }

    /**
     * Effective end: tournament row or brochure meta (optional).
     */
    public static function effective_end_date(?object $tournament): ?string
    {
        if (!$tournament) {
            return null;
        }
        $row = self::normalize_date_string($tournament->end_date ?? null);
        if ($row !== null) {
            return $row;
        }
        $tid = (int) ($tournament->id ?? 0);
        if ($tid <= 0 || !class_exists('ChessPodium_PdfBrochure')) {
            return null;
        }
        return self::normalize_date_string(ChessPodium_PdfBrochure::get_meta($tid, 'end_date'));
    }

    /**
     * Whether this tournament should be listed on the public calendar (admin opt-out).
     */
    public static function is_visible_on_calendar(?object $tournament): bool
    {
        if (!$tournament) {
            return false;
        }
        if (!isset($tournament->calendar_visible)) {
            return true;
        }
        return (int) $tournament->calendar_visible === 1;
    }

    /**
     * After brochure save: copy dates to tournament row; update calendar visibility only when the brochure form includes the flag.
     *
     * @param array<string, mixed> $data Brochure payload (start_date / end_date strings).
     * @param array<string, mixed> $post Raw $_POST (use calendar_visible_present + calendar_visible).
     */
    public static function apply_brochure_save_to_tournament(int $tournamentId, array $data, array $post): void
    {
        $start = isset($data['start_date']) ? (string) $data['start_date'] : '';
        $end = isset($data['end_date']) ? (string) $data['end_date'] : '';
        $vis = null;
        if (isset($post['calendar_visible_present'])) {
            $vis = !empty($post['calendar_visible']) ? 1 : 0;
        }
        self::patch_tournament_calendar_row($tournamentId, $start, $end, $vis);
    }

    /**
     * @param int|null $visible null = leave calendar_visible unchanged
     */
    public static function patch_tournament_calendar_row(int $tournamentId, string $start, string $end, ?int $visible): void
    {
        if ($tournamentId <= 0) {
            return;
        }
        global $wpdb;
        $table = $wpdb->prefix . 'regina_tournaments';
        $sd = self::normalize_date_string($start);
        $ed = self::normalize_date_string($end);
        $row = [
            'start_date' => $sd,
            'end_date' => $ed,
        ];
        $formats = ['%s', '%s'];
        if ($visible !== null) {
            $row['calendar_visible'] = $visible ? 1 : 0;
            $formats[] = '%d';
        }
        $wpdb->update($table, $row, ['id' => $tournamentId], $formats, ['%d']);
    }

    /**
     * Update tournament row dates + calendar flag (from overview quick form).
     *
     * @param int    $tournamentId Tournament ID.
     * @param string $start        Y-m-d or empty.
     * @param string $end          Y-m-d or empty.
     * @param int    $visible      0 or 1.
     */
    public static function update_tournament_schedule_row(int $tournamentId, string $start, string $end, int $visible): void
    {
        self::patch_tournament_calendar_row($tournamentId, $start, $end, $visible);
    }

    /**
     * Preview image URL: first gallery photo, else brochure logo, else site default (same as tournament list cards).
     */
    public static function get_tournament_preview_image_url(object $tournament): string
    {
        $tid = (int) ($tournament->id ?? 0);
        if ($tid <= 0 || !class_exists('ChessPodiumPlugin')) {
            return '';
        }
        $photos = ChessPodiumPlugin::get_photos($tid);
        if (!empty($photos[0]->photo_url)) {
            return (string) $photos[0]->photo_url;
        }
        if (class_exists('ChessPodium_PdfBrochure')) {
            $brochureLogo = ChessPodium_PdfBrochure::get_meta($tid, 'brochure_logo');
            if (is_string($brochureLogo) && $brochureLogo !== '') {
                return $brochureLogo;
            }
        }
        return ChessPodiumPlugin::get_default_logo_url();
    }

    /**
     * @return list<array{tournament: object, start: string, end: string, url: string, thumb_url: string}>
     */
    public static function collect_events(bool $includeOngoing = true, bool $includePast = true): array
    {
        if (!class_exists('ChessPodiumPlugin')) {
            return [];
        }
        $today = wp_date('Y-m-d', null, wp_timezone());
        $out = [];
        foreach (ChessPodiumPlugin::get_tournaments() as $t) {
            if (!self::is_visible_on_calendar($t)) {
                continue;
            }
            $start = self::effective_start_date($t);
            if ($start === null) {
                continue;
            }
            $end = self::effective_end_date($t) ?? $start;
            $tid = (int) ($t->id ?? 0);
            if ($tid <= 0) {
                continue;
            }
            if (!$includePast && $end < $today) {
                continue;
            }
            $finished = (int) ($t->current_round ?? 0) >= (int) ($t->rounds_total ?? 0) && (int) ($t->rounds_total ?? 0) > 0;
            $isFuture = ($start >= $today);
            $ongoing = $includeOngoing && ($start < $today && $end >= $today) && !$finished;
            $isPast = ($end < $today);
            if (!$isFuture && !$ongoing && !($includePast && $isPast)) {
                continue;
            }
            $out[] = [
                'tournament' => $t,
                'start' => $start,
                'end' => $end,
                'url' => ChessPodiumPlugin::get_public_tournament_view_url($tid),
                'thumb_url' => self::get_tournament_preview_image_url($t),
            ];
        }
        usort($out, static function ($a, $b) use ($today) {
            $endA = $a['end'] ?? $a['start'];
            $endB = $b['end'] ?? $b['start'];
            $aPast = ($endA < $today);
            $bPast = ($endB < $today);
            if ($aPast !== $bPast) {
                return $aPast ? 1 : -1;
            }
            if ($aPast) {
                return strcmp($b['start'], $a['start']);
            }

            return strcmp($a['start'], $b['start']);
        });
        return $out;
    }

    /**
     * @param array<string, mixed> $atts
     */
    public static function render_shortcode($atts = [], $content = null, $tag = ''): string
    {
        $atts = shortcode_atts(
            [
                'include_ongoing' => '1',
                'include_past' => '1',
                'show_list' => '1',
                'thumbnails' => '1',
                'month' => '',
            ],
            $atts,
            'chess_podium_events'
        );
        $includeOngoing = filter_var($atts['include_ongoing'], FILTER_VALIDATE_BOOLEAN);
        $includePast = filter_var($atts['include_past'], FILTER_VALIDATE_BOOLEAN);
        $showList = filter_var($atts['show_list'], FILTER_VALIDATE_BOOLEAN);
        $showThumbnails = filter_var($atts['thumbnails'], FILTER_VALIDATE_BOOLEAN);
        $monthParam = sanitize_text_field((string) $atts['month']);
        if ($monthParam === '' && isset($_GET['cp_ev_month'])) {
            $monthParam = sanitize_text_field(wp_unslash((string) $_GET['cp_ev_month']));
        }
        if (!preg_match('/^\d{4}-\d{2}$/', $monthParam)) {
            $monthParam = wp_date('Y-m', null, wp_timezone());
        }
        $events = self::collect_events($includeOngoing, $includePast);
        $events = apply_filters('chess_podium_calendar_events', $events, $atts);

        $todayYmd = wp_date('Y-m-d', null, wp_timezone());
        $byDay = [];
        foreach ($events as $ev) {
            $s = $ev['start'];
            $e = $ev['end'] ?? $s;
            $tsS = strtotime($s . ' 12:00:00');
            $tsE = strtotime($e . ' 12:00:00');
            if ($tsS === false || $tsE === false) {
                continue;
            }
            for ($t = $tsS; $t <= $tsE; $t += DAY_IN_SECONDS) {
                $d = gmdate('Y-m-d', $t);
                if (!isset($byDay[$d])) {
                    $byDay[$d] = [];
                }
                $byDay[$d][] = $ev;
            }
        }

        ob_start();
        $tz = wp_timezone();
        try {
            $monthBase = new DateTimeImmutable($monthParam . '-01', $tz);
        } catch (\Exception $e) {
            $monthBase = new DateTimeImmutable('first day of this month', $tz);
        }
        $prevYm = $monthBase->modify('-1 month')->format('Y-m');
        $nextYm = $monthBase->modify('+1 month')->format('Y-m');
        $prevUrl = esc_url(add_query_arg('cp_ev_month', $prevYm));
        $nextUrl = esc_url(add_query_arg('cp_ev_month', $nextYm));
        $monthLabel = wp_date('F Y', $monthBase->getTimestamp(), $tz);
        ?>
<div class="cp-events-calendar-wrap" data-cp-events="1">
<style>
.cp-events-calendar-wrap{max-width:920px;margin:1.5rem auto;font-family:inherit;color:#1e293b;}
.cp-events-cal-head{display:flex;align-items:center;justify-content:space-between;gap:1rem;margin-bottom:1rem;flex-wrap:wrap;}
.cp-events-cal-head a{text-decoration:none;padding:.35rem .75rem;border:1px solid #cbd5e1;border-radius:6px;background:#fff;}
.cp-events-cal-head a:hover{background:#f1f5f9;}
.cp-events-cal-title{font-size:1.25rem;font-weight:700;margin:0;}
.cp-events-cal-scroll{overflow-x:auto;-webkit-overflow-scrolling:touch;overscroll-behavior-x:contain;border-radius:8px;scrollbar-width:thin;}
.cp-events-cal-grid{display:grid;grid-template-columns:repeat(7,minmax(5.75rem,1fr));grid-auto-rows:minmax(5.75rem,auto);gap:2px;background:#cbd5e1;border:1px solid #cbd5e1;border-radius:8px;overflow:hidden;align-items:stretch;width:100%;}
.cp-events-cal-dow,.cp-events-cal-cell{background:#fff;font-size:.8rem;}
.cp-events-cal-dow{font-weight:600;text-align:center;background:#e2e8f0;padding:.4rem .25rem;min-height:2.25rem;display:flex;align-items:center;justify-content:center;line-height:1.2;}
.cp-events-cal-cell{display:flex;flex-direction:column;min-height:5.75rem;padding:5px 6px 6px;box-sizing:border-box;overflow:hidden;}
.cp-events-cal-cell.cp-ev-out{opacity:.35;background:#f8fafc;min-height:5.75rem;}
.cp-events-cal-cell.cp-ev-today{outline:2px solid #2563eb;outline-offset:-2px;}
.cp-events-cal-daynum{font-weight:700;color:#64748b;margin:0 0 4px;line-height:1;flex-shrink:0;}
.cp-events-cal-events{flex:1 1 auto;display:flex;flex-direction:column;gap:5px;width:100%;}
.cp-events-cal-cell a.cp-ev-cal-link{display:block;font-weight:700;font-size:.88rem;line-height:1.35;color:#1d4ed8;text-decoration:none;word-break:normal;overflow-wrap:break-word;hyphens:auto;white-space:normal;max-width:100%;}
.cp-events-cal-cell a.cp-ev-cal-link:hover{text-decoration:underline;color:#1e40af;}
.cp-events-cal-cell a.cp-ev-cal-link.cp-ev-cal-past{color:#64748b;font-weight:600;}
.cp-events-cal-cell a.cp-ev-cal-link.cp-ev-cal-past:hover{color:#475569;text-decoration:underline;}
@media (max-width:767px){
.cp-events-cal-scroll{margin:0 -0.25rem;padding:0 .25rem;}
.cp-events-cal-grid{min-width:40.25rem;}
.cp-events-cal-dow{font-size:.72rem;padding:.3rem .15rem;}
.cp-events-cal-cell{min-height:5rem;padding:4px 5px 5px;}
.cp-events-cal-cell a.cp-ev-cal-link{font-size:.8rem;line-height:1.3;}
.cp-events-list .cp-ev-date{min-width:0;flex:1 1 100%;}
}
.cp-events-list{margin-top:1.75rem;}
.cp-events-list h3{margin:0 0 .75rem;font-size:1.1rem;}
.cp-events-list ul{list-style:none;margin:0;padding:0;}
.cp-events-list li.cp-ev-row{margin:0 0 .6rem;padding:0;border:1px solid #e2e8f0;border-radius:8px;background:#fff;overflow:hidden;}
.cp-events-list li.cp-ev-row.cp-ev-past{opacity:.88;}
.cp-events-list li.cp-ev-row .cp-ev-row-link{display:flex;align-items:center;gap:.65rem;padding:.5rem .65rem;text-decoration:none;color:inherit;min-width:0;width:100%;box-sizing:border-box;}
.cp-events-list li.cp-ev-row .cp-ev-row-link:hover{background:#f8fafc;}
.cp-events-list .cp-ev-thumb-wrap{flex-shrink:0;width:72px;height:45px;border-radius:6px;overflow:hidden;background:#2c3e50;display:block;}
.cp-events-list .cp-ev-thumb-wrap img{width:100%;height:100%;object-fit:cover;display:block;}
.cp-events-list .cp-ev-body{display:flex;flex-wrap:wrap;gap:.25rem .75rem;align-items:baseline;min-width:0;flex:1;}
.cp-events-list .cp-ev-date{font-weight:600;color:#0f172a;min-width:7.5rem;}
.cp-events-list .cp-ev-title{font-weight:600;color:#1d4ed8;}
.cp-events-list .cp-ev-meta{color:#64748b;font-size:.85rem;}
</style>
<div class="cp-events-cal-head">
<a href="<?php echo $prevUrl; ?>">&larr; <?php echo esc_html__('Previous', 'chess-podium'); ?></a>
<h2 class="cp-events-cal-title"><?php echo esc_html($monthLabel); ?></h2>
<a href="<?php echo $nextUrl; ?>"><?php echo esc_html__('Next', 'chess-podium'); ?> &rarr;</a>
</div>
<div class="cp-events-cal-scroll">
<div class="cp-events-cal-grid" role="grid" aria-label="<?php echo esc_attr__('Tournament calendar', 'chess-podium'); ?>">
        <?php
        $startOfWeek = (int) get_option('start_of_week', 1);
        $startOfWeek = max(0, min(6, $startOfWeek));
        $wpLocale = isset($GLOBALS['wp_locale']) ? $GLOBALS['wp_locale'] : null;
        for ($i = 0; $i < 7; $i++) {
            $dow = ($startOfWeek + $i) % 7;
            if ($wpLocale && isset($wpLocale->weekday_abbrev[$dow])) {
                $wn = $wpLocale->weekday_abbrev[$dow];
            } elseif ($wpLocale && isset($wpLocale->weekday[$dow])) {
                $wn = function_exists('mb_substr')
                    ? mb_substr($wpLocale->weekday[$dow], 0, 3)
                    : substr($wpLocale->weekday[$dow], 0, 3);
            } else {
                $wn = wp_date('D', strtotime('2024-01-07 12:00:00 UTC') + $dow * DAY_IN_SECONDS, $tz);
            }
            echo '<div class="cp-events-cal-dow" role="columnheader">' . esc_html($wn) . '</div>';
        }
        $y = (int) $monthBase->format('Y');
        $m = (int) $monthBase->format('n');
        $daysInMonth = (int) $monthBase->format('t');
        $firstDow = (int) $monthBase->format('w');
        $pad = ($firstDow - $startOfWeek + 7) % 7;
        $totalCells = (int) ceil(($pad + $daysInMonth) / 7) * 7;
        for ($i = 0; $i < $totalCells; $i++) {
            $dayNum = $i - $pad + 1;
            if ($dayNum < 1 || $dayNum > $daysInMonth) {
                echo '<div class="cp-events-cal-cell cp-ev-out" role="gridcell"></div>';
                continue;
            }
            $ymd = sprintf('%04d-%02d-%02d', $y, $m, $dayNum);
            $isToday = ($ymd === $todayYmd);
            $cellClass = 'cp-events-cal-cell' . ($isToday ? ' cp-ev-today' : '');
            echo '<div class="' . esc_attr($cellClass) . '" role="gridcell">';
            echo '<div class="cp-events-cal-daynum">' . esc_html((string) $dayNum) . '</div>';
            echo '<div class="cp-events-cal-events">';
            if (!empty($byDay[$ymd])) {
                $seen = [];
                foreach ($byDay[$ymd] as $ev) {
                    $tid = (int) ($ev['tournament']->id ?? 0);
                    if ($tid <= 0 || isset($seen[$tid])) {
                        continue;
                    }
                    $seen[$tid] = true;
                    $name = (string) ($ev['tournament']->name ?? '');
                    $endEv = $ev['end'] ?? $ev['start'];
                    $linkPast = ($endEv < $todayYmd);
                    $linkClass = 'cp-ev-cal-link' . ($linkPast ? ' cp-ev-cal-past' : '');
                    echo '<a class="' . esc_attr($linkClass) . '" href="' . esc_url($ev['url']) . '" title="' . esc_attr($name) . '">' . esc_html($name) . '</a>';
                }
            }
            echo '</div></div>';
        }
        ?>
</div>
</div>
        <?php if ($showList) : ?>
<div class="cp-events-list">
<h3><?php esc_html_e('Past, current & upcoming tournaments', 'chess-podium'); ?></h3>
<ul>
            <?php foreach ($events as $ev) :
                $t = $ev['tournament'];
                $name = (string) ($t->name ?? '');
                $city = isset($t->city) ? trim((string) $t->city) : '';
                $cr = (int) ($t->current_round ?? 0);
                $rt = (int) ($t->rounds_total ?? 0);
                $meta = $city !== '' ? $city : sprintf(__('Round %1$d / %2$d', 'chess-podium'), $cr, $rt);
                $endEv = $ev['end'] ?? $ev['start'];
                $isPastRow = ($endEv < $todayYmd);
                $thumbUrl = isset($ev['thumb_url']) ? esc_url((string) $ev['thumb_url']) : '';
                ?>
<li class="cp-ev-row<?php echo $isPastRow ? ' cp-ev-past' : ''; ?>">
<a class="cp-ev-row-link" href="<?php echo esc_url($ev['url']); ?>">
                <?php if ($showThumbnails && $thumbUrl !== '') : ?>
<span class="cp-ev-thumb-wrap"><img src="<?php echo $thumbUrl; ?>" alt="<?php echo esc_attr($name); ?>" loading="lazy" decoding="async"></span>
                <?php endif; ?>
<div class="cp-ev-body">
<span class="cp-ev-date"><?php echo esc_html(wp_date(get_option('date_format', 'Y-m-d'), strtotime($ev['start'] . ' 12:00:00'), wp_timezone())); ?><?php
                if (($ev['end'] ?? '') !== '' && $ev['end'] !== $ev['start']) {
                    echo ' – ';
                    echo esc_html(wp_date(get_option('date_format', 'Y-m-d'), strtotime($ev['end'] . ' 12:00:00'), wp_timezone()));
                }
                ?></span>
<span class="cp-ev-title"><?php echo esc_html($name); ?></span>
<span class="cp-ev-meta"><?php echo esc_html($meta); ?></span>
</div>
</a>
</li>
            <?php endforeach; ?>
            <?php if (empty($events)) : ?>
<li><?php esc_html_e('No tournaments with dates in this period. Add start/end dates in Chess Podium → tournament → Content (brochure) or Overview (quick schedule).', 'chess-podium'); ?></li>
            <?php endif; ?>
</ul>
</div>
        <?php endif; ?>
</div>
        <?php
        return (string) ob_get_clean();
    }
}
