<?php

declare(strict_types=1);

/**
 * 技師評論：按讚、收藏（不發 N 幣獎勵）。
 */

require_once __DIR__ . DIRECTORY_SEPARATOR . 'fate_rich_body.php';
require_once __DIR__ . DIRECTORY_SEPARATOR . 'fate_store_masseurs.php';

function fate_masseur_review_engagement_ensure_schema(PDO $pdo): void
{
    static $done = false;
    if ($done) {
        return;
    }
    fate_masseur_ensure_tables($pdo);
    try {
        $cols = [];
        foreach ($pdo->query('SHOW COLUMNS FROM `fate_masseur_reviews`')->fetchAll(PDO::FETCH_ASSOC) as $c) {
            $cols[(string) $c['Field']] = true;
        }
        if (!isset($cols['like_count'])) {
            $pdo->exec('ALTER TABLE `fate_masseur_reviews` ADD COLUMN `like_count` INT UNSIGNED NOT NULL DEFAULT 0 AFTER `paid_preview_chars`');
        }
        if (!isset($cols['favorite_count'])) {
            $pdo->exec('ALTER TABLE `fate_masseur_reviews` ADD COLUMN `favorite_count` INT UNSIGNED NOT NULL DEFAULT 0 AFTER `like_count`');
        }
    } catch (Throwable) {
        /* 略過 */
    }

    try {
        $pdo->exec(<<<'SQL'
CREATE TABLE IF NOT EXISTS `fate_masseur_review_likes` (
  `id` INT UNSIGNED NOT NULL AUTO_INCREMENT,
  `review_id` INT UNSIGNED NOT NULL,
  `member_id` INT UNSIGNED NOT NULL,
  `created_at` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
  PRIMARY KEY (`id`),
  UNIQUE KEY `uq_review_member` (`review_id`, `member_id`),
  KEY `idx_review` (`review_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci
SQL);
        $pdo->exec(<<<'SQL'
CREATE TABLE IF NOT EXISTS `fate_masseur_review_favorites` (
  `id` INT UNSIGNED NOT NULL AUTO_INCREMENT,
  `review_id` INT UNSIGNED NOT NULL,
  `member_id` INT UNSIGNED NOT NULL,
  `favorited_at` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
  PRIMARY KEY (`id`),
  UNIQUE KEY `uq_review_member` (`review_id`, `member_id`),
  KEY `idx_review` (`review_id`),
  KEY `idx_member_fav` (`member_id`, `favorited_at`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci
SQL);
    } catch (Throwable) {
        /* 略過 */
    }

    $done = true;
}

function fate_masseur_review_engagement_recount_likes(PDO $pdo, int $reviewId): void
{
    if ($reviewId <= 0) {
        return;
    }
    fate_masseur_review_engagement_ensure_schema($pdo);
    try {
        $pdo->prepare(
            'UPDATE `fate_masseur_reviews` SET `like_count` = (
                SELECT COUNT(*) FROM `fate_masseur_review_likes` l WHERE l.`review_id` = ?
            ) WHERE `id` = ?'
        )->execute([$reviewId, $reviewId]);
    } catch (Throwable) {
        /* 略過 */
    }
}

function fate_masseur_review_engagement_recount_favorites(PDO $pdo, int $reviewId): void
{
    if ($reviewId <= 0) {
        return;
    }
    fate_masseur_review_engagement_ensure_schema($pdo);
    try {
        $pdo->prepare(
            'UPDATE `fate_masseur_reviews` SET `favorite_count` = (
                SELECT COUNT(*) FROM `fate_masseur_review_favorites` f WHERE f.`review_id` = ?
            ) WHERE `id` = ?'
        )->execute([$reviewId, $reviewId]);
    } catch (Throwable) {
        /* 略過 */
    }
}

function fate_masseur_review_engagement_get(PDO $pdo, int $reviewId): ?array
{
    if ($reviewId <= 0) {
        return null;
    }
    fate_masseur_review_engagement_ensure_schema($pdo);
    try {
        $st = $pdo->prepare('SELECT * FROM `fate_masseur_reviews` WHERE `id` = ? LIMIT 1');
        $st->execute([$reviewId]);
        $row = $st->fetch(PDO::FETCH_ASSOC);

        return is_array($row) ? $row : null;
    } catch (Throwable) {
        return null;
    }
}

/**
 * @param list<int> $reviewIds
 * @return array<int,bool>
 */
function fate_masseur_review_like_viewer_map(PDO $pdo, int $memberId, array $reviewIds): array
{
    fate_masseur_review_engagement_ensure_schema($pdo);
    if ($memberId <= 0 || $reviewIds === []) {
        return [];
    }
    $reviewIds = array_values(array_unique(array_filter(array_map('intval', $reviewIds), static fn (int $id): bool => $id > 0)));
    if ($reviewIds === []) {
        return [];
    }
    $place = implode(',', array_fill(0, count($reviewIds), '?'));
    try {
        $st = $pdo->prepare("SELECT `review_id` FROM `fate_masseur_review_likes` WHERE `member_id` = ? AND `review_id` IN ($place)");
        $st->execute(array_merge([$memberId], $reviewIds));
        $out = [];
        foreach ($st->fetchAll(PDO::FETCH_COLUMN) ?: [] as $rid) {
            $out[(int) $rid] = true;
        }

        return $out;
    } catch (Throwable) {
        return [];
    }
}

/**
 * @param list<int> $reviewIds
 * @return array<int,bool>
 */
function fate_masseur_review_favorite_viewer_map(PDO $pdo, int $memberId, array $reviewIds): array
{
    fate_masseur_review_engagement_ensure_schema($pdo);
    if ($memberId <= 0 || $reviewIds === []) {
        return [];
    }
    $reviewIds = array_values(array_unique(array_filter(array_map('intval', $reviewIds), static fn (int $id): bool => $id > 0)));
    if ($reviewIds === []) {
        return [];
    }
    $place = implode(',', array_fill(0, count($reviewIds), '?'));
    try {
        $st = $pdo->prepare("SELECT `review_id` FROM `fate_masseur_review_favorites` WHERE `member_id` = ? AND `review_id` IN ($place)");
        $st->execute(array_merge([$memberId], $reviewIds));
        $out = [];
        foreach ($st->fetchAll(PDO::FETCH_COLUMN) ?: [] as $rid) {
            $out[(int) $rid] = true;
        }

        return $out;
    } catch (Throwable) {
        return [];
    }
}

/**
 * @param list<array<string,mixed>> $rows
 * @return list<array<string,mixed>>
 */
function fate_masseur_review_engagement_attach(PDO $pdo, array $rows, int $viewerId): array
{
    if ($rows === []) {
        return $rows;
    }
    fate_masseur_review_engagement_ensure_schema($pdo);
    $reviewIds = array_map(static fn ($r) => (int) ($r['id'] ?? 0), $rows);
    $likedMap = $viewerId > 0 ? fate_masseur_review_like_viewer_map($pdo, $viewerId, $reviewIds) : [];
    $favMap = $viewerId > 0 ? fate_masseur_review_favorite_viewer_map($pdo, $viewerId, $reviewIds) : [];

    foreach ($rows as &$r) {
        $rid = (int) ($r['id'] ?? 0);
        $r['like_count'] = (int) ($r['like_count'] ?? 0);
        $r['favorite_count'] = (int) ($r['favorite_count'] ?? 0);
        $r['viewer_liked'] = isset($likedMap[$rid]);
        $r['viewer_favorited'] = isset($favMap[$rid]);
    }
    unset($r);

    return $rows;
}

/** @return array{ok:bool,liked:bool,like_count:int,error:?string} */
function fate_masseur_review_like_toggle(PDO $pdo, int $reviewId, int $memberId): array
{
    fate_masseur_review_engagement_ensure_schema($pdo);
    if ($memberId <= 0) {
        return ['ok' => false, 'liked' => false, 'like_count' => 0, 'error' => '請先登入。'];
    }
    if ($reviewId <= 0) {
        return ['ok' => false, 'liked' => false, 'like_count' => 0, 'error' => '評論無效。'];
    }
    $review = fate_masseur_review_engagement_get($pdo, $reviewId);
    if ($review === null || (int) ($review['is_hidden'] ?? 0) === 1) {
        return ['ok' => false, 'liked' => false, 'like_count' => 0, 'error' => '找不到評論。'];
    }
    if (!fate_masseur_reviews_enabled()) {
        return ['ok' => false, 'liked' => false, 'like_count' => 0, 'error' => '評論功能未開放。'];
    }

    try {
        $st = $pdo->prepare('SELECT `id` FROM `fate_masseur_review_likes` WHERE `review_id` = ? AND `member_id` = ? LIMIT 1');
        $st->execute([$reviewId, $memberId]);
        $existing = $st->fetchColumn();
        if ($existing !== false) {
            $pdo->prepare('DELETE FROM `fate_masseur_review_likes` WHERE `id` = ?')->execute([(int) $existing]);
            $liked = false;
        } else {
            $pdo->prepare('INSERT INTO `fate_masseur_review_likes` (`review_id`, `member_id`) VALUES (?, ?)')
                ->execute([$reviewId, $memberId]);
            $liked = true;
        }
        fate_masseur_review_engagement_recount_likes($pdo, $reviewId);
        $fresh = fate_masseur_review_engagement_get($pdo, $reviewId);
        $cnt = (int) ($fresh['like_count'] ?? 0);

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

/** @return array{ok:bool,favorited:bool,favorite_count:int,error:?string} */
function fate_masseur_review_favorite_toggle(PDO $pdo, int $memberId, int $reviewId): array
{
    fate_masseur_review_engagement_ensure_schema($pdo);
    if ($memberId <= 0) {
        return ['ok' => false, 'favorited' => false, 'favorite_count' => 0, 'error' => '請先登入。'];
    }
    if ($reviewId <= 0) {
        return ['ok' => false, 'favorited' => false, 'favorite_count' => 0, 'error' => '評論無效。'];
    }
    $review = fate_masseur_review_engagement_get($pdo, $reviewId);
    if ($review === null || (int) ($review['is_hidden'] ?? 0) === 1) {
        return ['ok' => false, 'favorited' => false, 'favorite_count' => 0, 'error' => '找不到評論。'];
    }
    if (!fate_masseur_reviews_enabled()) {
        return ['ok' => false, 'favorited' => false, 'favorite_count' => 0, 'error' => '評論功能未開放。'];
    }

    try {
        $st = $pdo->prepare('SELECT `id` FROM `fate_masseur_review_favorites` WHERE `member_id` = ? AND `review_id` = ? LIMIT 1');
        $st->execute([$memberId, $reviewId]);
        $existing = $st->fetchColumn();
        if ($existing !== false) {
            $pdo->prepare('DELETE FROM `fate_masseur_review_favorites` WHERE `id` = ?')->execute([(int) $existing]);
            $favorited = false;
        } else {
            $pdo->prepare(
                'INSERT INTO `fate_masseur_review_favorites` (`member_id`, `review_id`, `favorited_at`) VALUES (?, ?, NOW())'
            )->execute([$memberId, $reviewId]);
            $favorited = true;
        }
        fate_masseur_review_engagement_recount_favorites($pdo, $reviewId);
        $fresh = fate_masseur_review_engagement_get($pdo, $reviewId);
        $cnt = (int) ($fresh['favorite_count'] ?? 0);

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

function fate_masseur_review_engagement_delete_for_review(PDO $pdo, int $reviewId): void
{
    if ($reviewId <= 0) {
        return;
    }
    fate_masseur_review_engagement_ensure_schema($pdo);
    try {
        $pdo->prepare('DELETE FROM `fate_masseur_review_likes` WHERE `review_id` = ?')->execute([$reviewId]);
        $pdo->prepare('DELETE FROM `fate_masseur_review_favorites` WHERE `review_id` = ?')->execute([$reviewId]);
    } catch (Throwable) {
        /* 略過 */
    }
}

function fate_masseur_review_engagement_delete_for_masseur(PDO $pdo, int $masseurId): void
{
    if ($masseurId <= 0) {
        return;
    }
    fate_masseur_review_engagement_ensure_schema($pdo);
    try {
        $pdo->prepare(
            'DELETE l FROM `fate_masseur_review_likes` l
             INNER JOIN `fate_masseur_reviews` r ON r.`id` = l.`review_id`
             WHERE r.`masseur_id` = ?'
        )->execute([$masseurId]);
        $pdo->prepare(
            'DELETE f FROM `fate_masseur_review_favorites` f
             INNER JOIN `fate_masseur_reviews` r ON r.`id` = f.`review_id`
             WHERE r.`masseur_id` = ?'
        )->execute([$masseurId]);
    } catch (Throwable) {
        /* 略過 */
    }
}

function fate_masseur_review_excerpt(string $body, int $maxLen = 140): string
{
    $plain = fate_rich_body_plain_text($body);
    if ($plain === '') {
        return '';
    }
    if (function_exists('mb_strlen') && mb_strlen($plain) > $maxLen) {
        return mb_substr($plain, 0, $maxLen) . '…';
    }
    if (strlen($plain) > $maxLen) {
        return substr($plain, 0, $maxLen) . '…';
    }

    return $plain;
}

function fate_masseur_review_favorite_url(int $storeId, int $masseurId, int $reviewId): string
{
    return 'store.php?id=' . max(0, $storeId) . '#masseur-review-' . $masseurId . '-paid-' . $reviewId;
}

/**
 * @return list<array<string,mixed>>
 */
function fate_masseur_review_favorites_list_for_member(PDO $pdo, int $memberId, int $limit = 100): array
{
    fate_masseur_review_engagement_ensure_schema($pdo);
    if ($memberId <= 0) {
        return [];
    }
    $limit = max(1, min(200, $limit));
    $memberQt = fate_masseur_member_table_qualified();
    $sql = 'SELECT f.`favorited_at`, r.`id` AS `review_id`, r.`body`, r.`masseur_id`, r.`member_id` AS `author_member_id`, r.`is_paid`, r.`is_hidden`, ';
    $sql .= 'm.`name` AS `masseur_name`, m.`spa_store_id`, ';
    $sql .= $memberQt !== null
        ? "COALESCE(NULLIF(TRIM(mb.`display_name`), ''), mb.`username`, CONCAT('會員#', r.`member_id`)) AS `author_name` "
        : "CONCAT('會員#', r.`member_id`) AS `author_name` ";
    $sql .= 'FROM `fate_masseur_review_favorites` f ';
    $sql .= 'INNER JOIN `fate_masseur_reviews` r ON r.`id` = f.`review_id` ';
    $sql .= 'INNER JOIN `fate_store_masseurs` m ON m.`id` = r.`masseur_id` ';
    if ($memberQt !== null) {
        $sql .= "LEFT JOIN $memberQt mb ON mb.`id` = r.`member_id` ";
    }
    $sql .= 'WHERE f.`member_id` = ? ORDER BY f.`favorited_at` DESC, f.`id` DESC LIMIT ' . $limit;

    try {
        $st = $pdo->prepare($sql);
        $st->execute([$memberId]);
        $rows = $st->fetchAll(PDO::FETCH_ASSOC) ?: [];
    } catch (Throwable) {
        return [];
    }

    $out = [];
    foreach ($rows as $row) {
        $storeId = (int) ($row['spa_store_id'] ?? 0);
        $masseurId = (int) ($row['masseur_id'] ?? 0);
        $reviewId = (int) ($row['review_id'] ?? 0);
        $hidden = (int) ($row['is_hidden'] ?? 0) === 1;
        $row['type_label'] = '技師評論';
        $row['excerpt'] = fate_masseur_review_excerpt((string) ($row['body'] ?? ''));
        $row['review_url'] = fate_masseur_review_favorite_url($storeId, $masseurId, $reviewId);
        $row['is_orphan'] = $hidden ? 1 : 0;
        $row['context_title'] = trim((string) ($row['masseur_name'] ?? '')) !== ''
            ? (string) $row['masseur_name']
            : ('技師 #' . $masseurId);
        $out[] = $row;
    }

    return $out;
}

function fate_masseur_review_favorites_count_for_member(PDO $pdo, int $memberId): int
{
    fate_masseur_review_engagement_ensure_schema($pdo);
    if ($memberId <= 0) {
        return 0;
    }
    try {
        $st = $pdo->prepare('SELECT COUNT(*) FROM `fate_masseur_review_favorites` WHERE `member_id` = ?');
        $st->execute([$memberId]);

        return (int) $st->fetchColumn();
    } catch (Throwable) {
        return 0;
    }
}
