<?php
declare(strict_types=1);

require_once __DIR__ . '/FreeTier.php';
require_once __DIR__ . '/CaseStore.php';

/**
 * Persistent tool-run results per case (premium "Saved analyses" feature).
 *
 * Every successful Korrespond / Advocate / BVJ / Deep Research / Discrepancy / Timeline run
 * for a paid (Plus or Pro) user — including active trial — is written to `case_tool_results`.
 * Free users do not persist results; save() silently no-ops for them.
 *
 * Storage layout:
 *   user_id        — session user (may be a family member)
 *   owner_user_id  — CaseStore::caseResolveClientId result; whose corpus the run touched
 *   tool           — tool slug
 *   input_payload  — the entire request body (used by Re-run)
 *   output_payload — the entire tool response
 *   used_case_context + case_doc_ids — true when the user toggled "Bruk min sak"
 */
final class CaseResults
{
    /** Tools that participate in the saved-results system. Other tools (search, corpus, etc.) are not persisted. */
    public const ELIGIBLE_TOOLS = [
        'korrespond',
        'advocate',
        'barnevernet',
        'deep-research',
        'discrepancy',
        'timeline',
        'summarize',
        'ask',
        'redact',
        'transcribe',
        'legal-analysis',
        'translate',
    ];

    /** True when the user is on a tier that gets saved results (Plus, Pro, or active Plus trial). */
    public static function isEnabled(int $userId): bool
    {
        if ($userId <= 0) {
            return false;
        }
        $tier = FreeTier::tier($userId);
        return FreeTier::isPaidTier($tier);
    }

    /**
     * Persist a completed tool run. Returns the new row id, or 0 if the user isn't eligible
     * (so callers can wrap unconditionally without if-branches).
     *
     * @param array $meta {
     *   used_case_context: 0|1,
     *   case_doc_ids:      int[],
     *   model:             string|null,
     *   latency_ms:        int|null,
     *   credits_charged:   int,
     * }
     */
    public static function save(
        int $userId,
        int $ownerUserId,
        string $tool,
        array $input,
        array $output,
        array $meta = []
    ): int {
        if (!self::isEnabled($userId)) {
            return 0;
        }
        if (!in_array($tool, self::ELIGIBLE_TOOLS, true)) {
            return 0;
        }
        if (!self::tableReady()) {
            return 0;
        }

        // Caller may supply an explicit title (e.g. from a manual "Save result" prompt).
        $title = isset($meta['title']) && trim((string)$meta['title']) !== ''
            ? mb_substr(trim((string)$meta['title']), 0, 200, 'UTF-8')
            : self::deriveTitle($tool, $input);

        $caseDocIds = $meta['case_doc_ids'] ?? [];
        if (!is_array($caseDocIds)) {
            $caseDocIds = [];
        }
        $caseDocIds = array_values(array_unique(array_map('intval', $caseDocIds)));

        $db = dbnmDb();
        $db->prepare(
            'INSERT INTO case_tool_results
                (user_id, owner_user_id, tool, title, used_case_context, case_doc_ids,
                 input_payload, output_payload, model, latency_ms, credits_charged, created_at)
             VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, NOW())'
        )->execute([
            $userId,
            $ownerUserId > 0 ? $ownerUserId : $userId,
            $tool,
            $title,
            !empty($meta['used_case_context']) ? 1 : 0,
            json_encode($caseDocIds, JSON_UNESCAPED_UNICODE),
            json_encode($input, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES),
            json_encode($output, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES),
            $meta['model'] ?? null,
            isset($meta['latency_ms']) ? (int)$meta['latency_ms'] : null,
            (int)($meta['credits_charged'] ?? 0),
        ]);

        return (int)$db->lastInsertId();
    }

    /** List a user's saved results (also visible across family seats). */
    public static function listForUser(int $userId, int $limit = 50): array
    {
        if ($userId <= 0) {
            return [];
        }
        if (!self::tableReady()) {
            return [];
        }
        $ownerId = CaseStore::caseResolveClientId($userId);
        $db = dbnmDb();
        $stmt = $db->prepare(
            'SELECT id, user_id, owner_user_id, tool, title, used_case_context,
                    model, latency_ms, credits_charged, pinned, korr_status, created_at
             FROM case_tool_results
             WHERE owner_user_id = ? AND deleted_at IS NULL
             ORDER BY pinned DESC, created_at DESC
             LIMIT ' . max(1, min(200, $limit))
        );
        $stmt->execute([$ownerId]);
        return $stmt->fetchAll(PDO::FETCH_ASSOC) ?: [];
    }

    /** Single result row with full payloads, ownership-checked. */
    public static function get(int $userId, int $resultId): ?array
    {
        if ($userId <= 0 || $resultId <= 0) {
            return null;
        }
        if (!self::tableReady()) {
            return null;
        }
        $ownerId = CaseStore::caseResolveClientId($userId);
        $db = dbnmDb();
        $stmt = $db->prepare(
            'SELECT * FROM case_tool_results
             WHERE id = ? AND owner_user_id = ? AND deleted_at IS NULL LIMIT 1'
        );
        $stmt->execute([$resultId, $ownerId]);
        $row = $stmt->fetch(PDO::FETCH_ASSOC);
        if (!$row) {
            return null;
        }
        $row['case_doc_ids']   = json_decode((string)$row['case_doc_ids'],   true) ?: [];
        $row['input_payload']  = json_decode((string)$row['input_payload'],  true) ?: [];
        $row['output_payload'] = json_decode((string)$row['output_payload'], true) ?: [];
        return $row;
    }

    /** Soft-delete a result. Returns true if the row was found and deleted. */
    public static function softDelete(int $userId, int $resultId): bool
    {
        if ($userId <= 0 || $resultId <= 0) {
            return false;
        }
        if (!self::tableReady()) {
            return false;
        }
        $ownerId = CaseStore::caseResolveClientId($userId);
        $db = dbnmDb();
        $stmt = $db->prepare(
            'UPDATE case_tool_results
             SET deleted_at = NOW()
             WHERE id = ? AND owner_user_id = ? AND deleted_at IS NULL'
        );
        $stmt->execute([$resultId, $ownerId]);
        return $stmt->rowCount() > 0;
    }

    /** Toggle the pinned flag. Returns the new pinned state, or null if not found. */
    public static function togglePin(int $userId, int $resultId): ?bool
    {
        if ($userId <= 0 || $resultId <= 0) {
            return null;
        }
        if (!self::tableReady()) {
            return null;
        }
        $ownerId = CaseStore::caseResolveClientId($userId);
        $db = dbnmDb();
        $stmt = $db->prepare(
            'UPDATE case_tool_results
             SET pinned = 1 - pinned
             WHERE id = ? AND owner_user_id = ? AND deleted_at IS NULL'
        );
        $stmt->execute([$resultId, $ownerId]);
        if ($stmt->rowCount() === 0) {
            return null;
        }
        $check = $db->prepare('SELECT pinned FROM case_tool_results WHERE id = ?');
        $check->execute([$resultId]);
        return (bool)$check->fetchColumn();
    }

    /** Update the user-editable title. Returns true on success. */
    public static function updateTitle(int $userId, int $resultId, string $title): bool
    {
        $title = mb_substr(trim($title), 0, 200, 'UTF-8');
        if ($title === '') {
            return false;
        }
        if (!self::tableReady()) {
            return false;
        }
        $ownerId = CaseStore::caseResolveClientId($userId);
        $db = dbnmDb();
        $stmt = $db->prepare(
            'UPDATE case_tool_results
             SET title = ?
             WHERE id = ? AND owner_user_id = ? AND deleted_at IS NULL'
        );
        $stmt->execute([$title, $resultId, $ownerId]);
        return $stmt->rowCount() > 0;
    }

    /** Update the correspondence status (korrespond tool only). */
    public static function updateStatus(int $userId, int $id, string $status): bool
    {
        $allowed = ['draft', 'sent', 'replied', 'resolved'];
        if (!in_array($status, $allowed, true)) {
            return false;
        }
        if (!self::tableReady()) {
            return false;
        }
        $ownerId = CaseStore::caseResolveClientId($userId);
        $db = dbnmDb();
        $stmt = $db->prepare(
            "UPDATE case_tool_results
                SET korr_status = ?
              WHERE id = ? AND owner_user_id = ? AND tool = 'korrespond' AND deleted_at IS NULL"
        );
        $stmt->execute([$status, $id, $ownerId]);
        return $stmt->rowCount() > 0;
    }

    /** Human-readable Norwegian title hint per tool. */
    public static function toolLabel(string $tool): string
    {
        return [
            'korrespond'    => 'Korrespondanse',
            'advocate'      => 'Advokatutkast',
            'barnevernet'   => 'BVJ-analyse',
            'deep-research' => 'Dyp analyse',
            'discrepancy'   => 'Motstrid',
            'timeline'      => 'Tidslinje',
            'summarize'      => 'Sammendrag',
            'ask'            => 'Spørsmål & svar',
            'redact'         => 'Anonymisering',
            'transcribe'     => 'Transkripsjon',
            'legal-analysis' => 'Juridisk analyse',
            'translate'      => 'Oversettelse',
        ][$tool] ?? ucfirst($tool);
    }

    /** Tool icon (emoji for now, can swap to SVG later). */
    public static function toolIcon(string $tool): string
    {
        return [
            'korrespond'    => '✉️',
            'advocate'      => '⚖️',
            'barnevernet'   => '🛡️',
            'deep-research' => '🔬',
            'discrepancy'   => '🔍',
            'timeline'      => '📅',
            'summarize'      => '📝',
            'ask'            => '💬',
            'redact'         => '🖊️',
            'transcribe'     => '🎙️',
            'legal-analysis' => '⚖️🇳🇴',
            'translate'      => '🌐',
        ][$tool] ?? '📄';
    }

    /** Derive a default title from the input payload (best-effort per tool). */
    private static function deriveTitle(string $tool, array $input): string
    {
        $candidates = match ($tool) {
            'korrespond'    => [$input['goal'] ?? null, $input['narrative'] ?? null, $input['case_ref'] ?? null],
            'advocate'      => [$input['question'] ?? null, $input['facts'] ?? null, $input['topic'] ?? null],
            'barnevernet'   => [$input['document_type'] ?? null, $input['summary'] ?? null, $input['text'] ?? null],
            'deep-research' => [$input['question'] ?? null, $input['query'] ?? null, $input['topic'] ?? null],
            'discrepancy'   => [$input['focus'] ?? null, $input['context'] ?? null],
            'timeline'      => [$input['context'] ?? null, $input['text'] ?? null],
            'summarize'     => [$input['text'] ?? null],
            'ask'           => [$input['question'] ?? null],
            'redact'        => [$input['text'] ?? null],
            'transcribe'    => [$input['filename'] ?? null],
            'legal-analysis' => [$input['doc_type'] ?? null, $input['text'] ?? null],
            'translate'      => [$input['source_lang'] ?? null, $input['target_lang'] ?? null, $input['text'] ?? null],
            default         => [$input['title'] ?? null, $input['query'] ?? null, $input['text'] ?? null],
        };
        foreach ($candidates as $c) {
            $c = is_string($c) ? trim($c) : '';
            if ($c !== '') {
                return mb_substr($c, 0, 80, 'UTF-8');
            }
        }
        return self::toolLabel($tool) . ' — ' . date('j. M Y H:i');
    }

    /** Guard against deployment order: code may arrive just before the DB migration. */
    private static function tableReady(): bool
    {
        static $ready = null;
        if ($ready !== null) {
            return $ready;
        }
        try {
            $stmt = dbnmDb()->prepare(
                'SELECT COUNT(*) FROM information_schema.tables
                 WHERE table_schema = DATABASE() AND table_name = ?'
            );
            $stmt->execute(['case_tool_results']);
            $ready = ((int)$stmt->fetchColumn()) > 0;
        } catch (Throwable $e) {
            error_log('[CaseResults] table readiness check failed: ' . $e->getMessage());
            $ready = false;
        }
        return $ready;
    }
}
