<?php

declare(strict_types=1);

/**
 * 會員收藏討論區單一回文（文章）。
 */

require_once __DIR__ . DIRECTORY_SEPARATOR . 'fate_plugins.php';

/** @return list<string> */
function fate_post_favorite_tables_ddl(): array
{
    return [
        <<<'SQL'
CREATE TABLE IF NOT EXISTS `fate_forum_post_favorites` (
  `id` INT UNSIGNED NOT NULL AUTO_INCREMENT,
  `member_id` INT UNSIGNED NOT NULL,
  `post_id` BIGINT UNSIGNED NOT NULL,
  `favorited_at` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
  PRIMARY KEY (`id`),
  UNIQUE KEY `uq_member_post` (`member_id`, `post_id`),
  KEY `idx_post` (`post_id`),
  KEY `idx_member_fav` (`member_id`, `favorited_at`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci
SQL,
    ];
}

function fate_post_favorite_ensure_tables(PDO $pdo): void
{
    static $done = false;
    if ($done) {
        return;
    }
    $done = true;
    try {
        foreach (fate_post_favorite_tables_ddl() as $ddl) {
            $pdo->exec($ddl);
        }
        try {
            $pdo->exec(
                'ALTER TABLE `fate_forum_posts` ADD COLUMN IF NOT EXISTS `favorite_count` INT UNSIGNED NOT NULL DEFAULT 0 AFTER `like_count`'
            );
        } catch (Throwable) {
            $cols = $pdo->query("SHOW COLUMNS FROM `fate_forum_posts` LIKE 'favorite_count'")->fetchAll();
            if ($cols === []) {
                $pdo->exec('ALTER TABLE `fate_forum_posts` ADD COLUMN `favorite_count` INT UNSIGNED NOT NULL DEFAULT 0 AFTER `like_count`');
            }
        }
    } catch (Throwable) {
        try {
            $pdo->exec(
                'CREATE TABLE IF NOT EXISTS `fate_forum_post_favorites` (
                  `id` INT UNSIGNED NOT NULL AUTO_INCREMENT,
                  `member_id` INT UNSIGNED NOT NULL,
                  `post_id` BIGINT UNSIGNED NOT NULL,
                  `favorited_at` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
                  PRIMARY KEY (`id`),
                  UNIQUE KEY `uq_member_post` (`member_id`, `post_id`),
                  KEY `idx_post` (`post_id`),
                  KEY `idx_member_fav` (`member_id`, `favorited_at`)
                ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci'
            );
            $cols = $pdo->query("SHOW COLUMNS FROM `fate_forum_posts` LIKE 'favorite_count'")->fetchAll();
            if ($cols === []) {
                $pdo->exec('ALTER TABLE `fate_forum_posts` ADD COLUMN `favorite_count` INT UNSIGNED NOT NULL DEFAULT 0 AFTER `like_count`');
            }
        } catch (Throwable) {
            /* 略過 */
        }
    }
}

function fate_post_favorite_recount(PDO $pdo, int $postId): void
{
    if ($postId <= 0) {
        return;
    }
    fate_post_favorite_ensure_tables($pdo);
    try {
        $pdo->prepare(
            'UPDATE `fate_forum_posts` p SET `favorite_count` = (
                SELECT COUNT(*) FROM `fate_forum_post_favorites` f WHERE f.`post_id` = p.`id`
            ) WHERE p.`id` = ?'
        )->execute([$postId]);
    } catch (Throwable) {
        /* 略過 */
    }
}

function fate_post_favorite_forum_repo(): ?string
{
    $path = dirname(__DIR__) . DIRECTORY_SEPARATOR . 'forum' . DIRECTORY_SEPARATOR . 'includes' . DIRECTORY_SEPARATOR . 'forum_repo.php';

    return is_file($path) ? $path : null;
}

/** @return array{ok:bool,favorited:bool,error:?string} */
function fate_post_favorite_toggle(PDO $pdo, int $memberId, int $postId): array
{
    fate_post_favorite_ensure_tables($pdo);
    if ($memberId <= 0) {
        return ['ok' => false, 'favorited' => false, 'error' => '請先登入。'];
    }
    if ($postId <= 0) {
        return ['ok' => false, 'favorited' => false, 'error' => '文章無效。'];
    }
    if (!fate_store_forum_plugin_active()) {
        return ['ok' => false, 'favorited' => false, 'error' => '討論區未啟用。'];
    }
    $repo = fate_post_favorite_forum_repo();
    if ($repo === null) {
        return ['ok' => false, 'favorited' => false, 'error' => '討論區模組不存在。'];
    }
    require_once $repo;
    $post = forum_post_get($pdo, $postId);
    if ($post === null || (int) ($post['is_hidden'] ?? 0) === 1) {
        return ['ok' => false, 'favorited' => false, 'error' => '找不到文章。'];
    }
    $threadId = (int) ($post['thread_id'] ?? 0);
    $thread = forum_thread_get($pdo, $threadId, false);
    if ($thread === null) {
        return ['ok' => false, 'favorited' => false, 'error' => '主題不存在或已隱藏。'];
    }

    try {
        $chk = $pdo->prepare('SELECT `id` FROM `fate_forum_post_favorites` WHERE `member_id` = ? AND `post_id` = ? LIMIT 1');
        $chk->execute([$memberId, $postId]);
        $existing = $chk->fetchColumn();
        if ($existing !== false) {
            $pdo->prepare('DELETE FROM `fate_forum_post_favorites` WHERE `id` = ?')->execute([(int) $existing]);
            fate_post_favorite_recount($pdo, $postId);

            return ['ok' => true, 'favorited' => false, 'error' => null];
        }
        $pdo->prepare(
            'INSERT INTO `fate_forum_post_favorites` (`member_id`, `post_id`, `favorited_at`) VALUES (?, ?, NOW())'
        )->execute([$memberId, $postId]);
        fate_post_favorite_recount($pdo, $postId);

        return ['ok' => true, 'favorited' => true, 'error' => null];
    } catch (Throwable $e) {
        return ['ok' => false, 'favorited' => false, 'error' => '操作失敗：' . $e->getMessage()];
    }
}

/** @param list<int> $postIds @return array<int,bool> */
function fate_post_favorite_viewer_map(PDO $pdo, int $memberId, array $postIds): array
{
    fate_post_favorite_ensure_tables($pdo);
    if ($memberId <= 0) {
        return [];
    }
    $ids = array_values(array_unique(array_filter(array_map('intval', $postIds), static fn (int $id): bool => $id > 0)));
    if ($ids === []) {
        return [];
    }
    $place = implode(',', array_fill(0, count($ids), '?'));
    $out = [];
    try {
        $st = $pdo->prepare("SELECT `post_id` FROM `fate_forum_post_favorites` WHERE `member_id` = ? AND `post_id` IN ($place)");
        $st->execute(array_merge([$memberId], $ids));
        foreach ($st->fetchAll(PDO::FETCH_ASSOC) as $row) {
            $out[(int) $row['post_id']] = true;
        }
    } catch (Throwable) {
        return [];
    }

    return $out;
}

/** @param list<int> $postIds @return array<int,int> */
function fate_post_favorite_counts_map(PDO $pdo, array $postIds): array
{
    fate_post_favorite_ensure_tables($pdo);
    $ids = array_values(array_unique(array_filter(array_map('intval', $postIds), static fn (int $id): bool => $id > 0)));
    if ($ids === []) {
        return [];
    }
    $place = implode(',', array_fill(0, count($ids), '?'));
    $out = [];
    try {
        $st = $pdo->prepare(
            "SELECT `post_id`, COUNT(*) AS `favorite_count` FROM `fate_forum_post_favorites` WHERE `post_id` IN ($place) GROUP BY `post_id`"
        );
        $st->execute($ids);
        foreach ($st->fetchAll(PDO::FETCH_ASSOC) as $row) {
            $out[(int) $row['post_id']] = (int) ($row['favorite_count'] ?? 0);
        }
    } catch (Throwable) {
        return [];
    }

    return $out;
}

function fate_post_favorite_excerpt(string $html, int $maxLen = 140): string
{
    $text = trim(preg_replace('/\s+/u', ' ', strip_tags($html)) ?? '');
    if ($text === '') {
        return '（無文字內容）';
    }
    if (function_exists('mb_strlen') && function_exists('mb_substr')) {
        if (mb_strlen($text, 'UTF-8') <= $maxLen) {
            return $text;
        }

        return mb_substr($text, 0, $maxLen, 'UTF-8') . '…';
    }
    if (strlen($text) <= $maxLen) {
        return $text;
    }

    return substr($text, 0, $maxLen) . '…';
}

/** @param array<string,mixed> $row */
function fate_post_favorite_type_label(PDO $pdo, array $row): string
{
    $type = (string) ($row['type'] ?? 'general');
    if ($type === 'store') {
        $refId = (int) ($row['ref_id'] ?? 0);
        if ($refId > 0) {
            $bindFile = dirname(__DIR__) . DIRECTORY_SEPARATOR . 'forum' . DIRECTORY_SEPARATOR . 'includes' . DIRECTORY_SEPARATOR . 'forum_thread_bind.php';
            if (is_file($bindFile)) {
                require_once $bindFile;
                $summary = forum_store_summary($pdo, $refId);
                if ($summary !== null && ($summary['name'] ?? '') !== '') {
                    return '店家 · ' . (string) $summary['name'];
                }
            }
        }

        return '店家討論';
    }
    if ($type === 'masseur') {
        $refId = (int) ($row['ref_id'] ?? 0);
        if ($refId > 0) {
            $masseurFile = dirname(__DIR__) . DIRECTORY_SEPARATOR . 'forum' . DIRECTORY_SEPARATOR . 'includes' . DIRECTORY_SEPARATOR . 'forum_masseur.php';
            if (is_file($masseurFile)) {
                require_once $masseurFile;
                $mRow = forum_masseur_row($pdo, $refId);
                if ($mRow !== null && ($mRow['name'] ?? '') !== '') {
                    return '技師 · ' . (string) $mRow['name'];
                }
            }
        }

        return '技師討論';
    }

    return '綜合討論';
}

function fate_post_favorite_page_for_floor(PDO $pdo, int $threadId, int $floorNo, int $perPage = 20): int
{
    if ($threadId <= 0 || $floorNo <= 0) {
        return 1;
    }
    $perPage = max(1, $perPage);
    try {
        $st = $pdo->prepare(
            'SELECT COUNT(*) FROM `fate_forum_posts` WHERE `thread_id` = ? AND `is_hidden` = 0 AND `floor_no` <= ?'
        );
        $st->execute([$threadId, $floorNo]);
        $rank = (int) $st->fetchColumn();

        return max(1, (int) ceil($rank / $perPage));
    } catch (Throwable) {
        return 1;
    }
}

/** @param array<string,mixed> $row */
function fate_post_favorite_post_url(PDO $pdo, array $row, int $perPage = 20): string
{
    $threadId = (int) ($row['thread_id'] ?? 0);
    $postId = (int) ($row['post_id'] ?? 0);
    $floorNo = (int) ($row['floor_no'] ?? 0);
    $type = (string) ($row['type'] ?? 'general');
    $refId = (int) ($row['ref_id'] ?? 0);
    if ($threadId <= 0) {
        return 'forum/index.php';
    }
    $page = fate_post_favorite_page_for_floor($pdo, $threadId, $floorNo, $perPage);
    $qs = ['id' => $threadId];
    if ($page > 1) {
        $qs['page'] = $page;
    }
    if ($type === 'store' && $refId > 0) {
        $qs['store_id'] = $refId;
    } elseif ($type === 'masseur' && $refId > 0) {
        $qs['masseur_id'] = $refId;
    }
    $url = 'forum/thread.php?' . http_build_query($qs);
    if ($floorNo > 0) {
        $url .= '#floor-' . $floorNo;
    } elseif ($postId > 0) {
        $url .= '#post-' . $postId;
    }

    return $url;
}

/** @return list<array<string,mixed>> */
function fate_post_favorites_list_for_member(PDO $pdo, int $memberId, int $perPage = 20): array
{
    fate_post_favorite_ensure_tables($pdo);
    if ($memberId <= 0) {
        return [];
    }
    $repo = fate_post_favorite_forum_repo();
    if ($repo === null) {
        return [];
    }
    require_once $repo;
    try {
        $st = $pdo->prepare(
            'SELECT f.`id` AS `favorite_id`, f.`favorited_at`, f.`post_id`,
                    p.`thread_id`, p.`floor_no`, p.`body`, p.`created_at` AS `post_created_at`,
                    p.`author_member_id`, t.`title`, t.`type`, t.`ref_id`, t.`is_orphan`
             FROM `fate_forum_post_favorites` f
             INNER JOIN `fate_forum_posts` p ON p.`id` = f.`post_id` AND p.`is_hidden` = 0
             INNER JOIN `fate_forum_threads` t ON t.`id` = p.`thread_id` AND t.`is_hidden` = 0
             WHERE f.`member_id` = ?
             ORDER BY f.`favorited_at` DESC, f.`id` DESC'
        );
        $st->execute([$memberId]);
        $rows = $st->fetchAll(PDO::FETCH_ASSOC);
    } catch (Throwable) {
        return [];
    }
    if (!is_array($rows)) {
        return [];
    }
    $authorIds = array_map(static fn (array $row): int => (int) ($row['author_member_id'] ?? 0), $rows);
    $names = forum_member_names($pdo, $authorIds);
    $out = [];
    foreach ($rows as $row) {
        if (!is_array($row)) {
            continue;
        }
        $aid = (int) ($row['author_member_id'] ?? 0);
        $row['author_name'] = $names[$aid] ?? '會員';
        $row['type_label'] = fate_post_favorite_type_label($pdo, $row);
        $row['post_url'] = fate_post_favorite_post_url($pdo, $row, $perPage);
        $row['excerpt'] = fate_post_favorite_excerpt((string) ($row['body'] ?? ''));
        $out[] = $row;
    }

    return $out;
}

/**
 * 單一回文收藏按鈕（POST 至 forum/post_action.php）。
 */
function fate_post_favorite_render_forum_toggle(
    int $postId,
    bool $isFavorited,
    bool $loggedIn,
    string $csrf,
    int $threadId,
    int $page = 1,
    string $loginNext = '',
    int $favoriteCount = 0
): void {
    $countLabel = number_format(max(0, $favoriteCount));
    if (!$loggedIn) {
        $next = $loginNext !== '' ? $loginNext : rawurlencode('forum/thread.php?id=' . $threadId);
        echo '<a class="forum-post-fav-btn forum-post-fav-btn--guest" href="../login.php?next=' . htmlspecialchars($next, ENT_QUOTES, 'UTF-8') . '" title="登入後可收藏">☆ ' . htmlspecialchars($countLabel, ENT_QUOTES, 'UTF-8') . '</a>';

        return;
    }
    $active = $isFavorited ? ' is-active' : '';
    $icon = $isFavorited ? '★' : '☆';
    $title = $isFavorited ? '取消收藏此文章' : '收藏此文章';
    ?>
<form method="post" action="./post_action.php" class="forum-post-fav-form">
    <input type="hidden" name="csrf" value="<?= htmlspecialchars($csrf, ENT_QUOTES, 'UTF-8') ?>">
    <input type="hidden" name="action" value="favorite_post">
    <input type="hidden" name="post_id" value="<?= $postId ?>">
    <input type="hidden" name="thread_id" value="<?= $threadId ?>">
    <input type="hidden" name="page" value="<?= max(1, $page) ?>">
    <button type="submit" class="forum-post-fav-btn<?= $active ?>" title="<?= htmlspecialchars($title, ENT_QUOTES, 'UTF-8') ?>"><?= htmlspecialchars($icon, ENT_QUOTES, 'UTF-8') ?> <?= htmlspecialchars($countLabel, ENT_QUOTES, 'UTF-8') ?></button>
</form>
    <?php
}

/** 會員頁收藏列表取消收藏。 */
function fate_post_favorite_render_member_unfav(int $postId, string $csrf): void
{
    ?>
<form method="post" action="member_profile.php?tab=saved_threads" class="member-thread-fav-unfav-form">
    <input type="hidden" name="csrf" value="<?= htmlspecialchars($csrf, ENT_QUOTES, 'UTF-8') ?>">
    <input type="hidden" name="action" value="post_favorite_toggle">
    <input type="hidden" name="post_id" value="<?= $postId ?>">
    <button type="submit" class="member-thread-fav-unfav-btn" title="取消收藏">★ 取消收藏</button>
</form>
    <?php
}
