/**
 * Badges Component - File type, rating, tags badges
 */
import { resolveAssetStatusDotColor } from "../features/status/AssetStatusDotTheme.js";
import { getRuntimeEnrichmentState } from "../stores/runtimeEnrichmentState.js";
import { detectKind } from "../features/grid/AssetCardRenderer.js";

/**
 * Create file type badge (overlaid on thumbnail)
 */
function _buildCollisionTitle({ ext = "", filename = "", count = 0, paths = [] }: { ext?: any; filename?: any; count?: any; paths?: any[] } = {}) {
    const safeExt = String(ext || "").trim();
    const safeName = String(filename || "").trim();
    const n = Math.max(0, Number(count) || 0);
    const list = Array.isArray(paths)
        ? paths.map((p: any) => String(p || "").trim()).filter(Boolean)
        : [];
    if (n < 2) return `${safeExt} file`;
    const lines = [`${safeExt}+ name collision in current view (${n})`];
    if (safeName) lines.push(`Name: ${safeName}`);
    if (list.length) {
        lines.push("Paths:");
        for (const p of list.slice(0, 4)) lines.push(`- ${p}`);
        if (list.length > 4) lines.push(`- ... +${list.length - 4} more`);
    }
    lines.push("Click to select collisions in current view");
    return lines.join("\n");
}

export function createFileBadge(filename: any, kind: string, nameCollision = false, collisionMeta: Record<string, any> | null = null): HTMLElement {
    const badge = document.createElement("div");
    badge.className = "mjr-file-badge";

    const ext =
        String(filename || "")
            .split(".")
            .pop()
            ?.toUpperCase?.() || "";
    try {
        badge.dataset.mjrExt = ext;
    } catch (e: any) {
        console.debug?.(e);
    }

    const category = detectKind({ kind }, ext);

    const cssVarMap = {
        image: "--mjr-badge-image",
        video: "--mjr-badge-video",
        audio: "--mjr-badge-audio",
        model3d: "--mjr-badge-model3d",
    };
    const cssVar = (cssVarMap as Record<string, any>)[category];
    const bgColor = cssVar ? `var(${cssVar}, #607D8B)` : "#607D8B";

    const alertBg = "var(--mjr-badge-duplicate-alert, #ff1744)";
    const normalBg = bgColor;
    const currentBg = nameCollision ? alertBg : normalBg;
    badge.textContent = ext + (nameCollision ? "+" : "");
    badge.title = nameCollision
        ? _buildCollisionTitle({
              ext,
              filename,
              count: collisionMeta?.count,
              paths: collisionMeta?.paths,
          })
        : `${ext} file`;
    badge.style.cssText = `
        position: absolute;
        top: 6px;
        left: 6px;
        padding: 3px 8px;
        border-radius: 4px;
        font-size: 10px;
        font-weight: 700;
        background: ${currentBg};
        opacity: 0.85;
        color: white;
        text-transform: uppercase;
        pointer-events: auto;
        z-index: 10;
        letter-spacing: 0.5px;
        box-shadow: 0 2px 4px rgba(0,0,0,0.3);
        cursor: ${nameCollision ? "pointer" : "default"};
    `;
    try {
        badge.dataset.mjrBadgeBg = normalBg;
    } catch (e: any) {
        console.debug?.(e);
    }

    return badge;
}

export function setFileBadgeCollision(badgeEl: HTMLElement | null | undefined, nameCollision: boolean, collisionMeta: Record<string, any> | null = null): void {
    if (!badgeEl) return;
    try {
        const ext = badgeEl.dataset?.mjrExt || "";
        const normalBg = badgeEl.dataset?.mjrBadgeBg || "var(--mjr-badge-image, #607D8B)";
        const alertBg = "var(--mjr-badge-duplicate-alert, #ff1744)";
        badgeEl.textContent = String(ext || "") + (nameCollision ? "+" : "");
        badgeEl.title = nameCollision
            ? _buildCollisionTitle({
                  ext,
                  filename: collisionMeta?.filename || "",
                  count: collisionMeta?.count,
                  paths: collisionMeta?.paths,
              })
            : `${ext} file`;
        badgeEl.style.background = nameCollision ? alertBg : normalBg;
        badgeEl.style.cursor = nameCollision ? "pointer" : "default";
    } catch (e: any) {
        console.debug?.(e);
    }
}

function toBoolish(value: any) {
    if (value === true) return true;
    if (value === false) return false;
    if (value === 1 || value === "1") return true;
    if (value === 0 || value === "0") return false;
    return null;
}

function getFirstPresent(asset: any, keys: any[] = []) {
    if (!asset || typeof asset !== "object") return null;
    for (const key of keys) {
        if (asset[key] != null) return asset[key];
    }
    return null;
}

function hasNonEmptyText(value: any) {
    return typeof value === "string" && value.trim().length > 0;
}

function hasStructuredData(value: any) {
    if (Array.isArray(value)) return value.some((item: any) => String(item ?? "").trim().length > 0);
    if (value && typeof value === "object") return Object.keys(value).length > 0;
    if (typeof value !== "string") return false;

    const text = value.trim();
    if (!text || text === "[]" || text === "[ ]") return false;
    if (/^(null|none)$/i.test(text)) return false;

    if (
        (text.startsWith("[") && text.endsWith("]")) ||
        (text.startsWith("{") && text.endsWith("}"))
    ) {
        try {
            const parsed = JSON.parse(text);
            if (Array.isArray(parsed)) {
                return parsed.some((item: any) => String(item ?? "").trim().length > 0);
            }
            if (parsed && typeof parsed === "object") {
                return Object.keys(parsed).length > 0;
            }
            return Boolean(parsed);
        } catch (e: any) {
            console.debug?.(e);
        }
    }
    return true;
}

function detectAiInfo(asset: any) {
    const autoTagsValue = getFirstPresent(asset, [
        "auto_tags",
        "autoTags",
        "ai_auto_tags",
        "aiAutoTags",
        "suggested_tags",
        "suggestedTags",
    ]);
    const enhancedPromptValue = getFirstPresent(asset, [
        "enhanced_caption",
        "enhancedCaption",
        "enhanced_prompt",
        "enhancedPrompt",
        "ai_enhanced_prompt",
        "aiEnhancedPrompt",
    ]);

    const hasAutoTagsFlag = toBoolish(
        getFirstPresent(asset, [
            "has_ai_auto_tags",
            "hasAiAutoTags",
            "ai_has_auto_tags",
            "aiHasAutoTags",
        ]),
    );
    const hasEnhancedPromptFlag = toBoolish(
        getFirstPresent(asset, [
            "has_ai_enhanced_caption",
            "hasAiEnhancedCaption",
            "ai_has_enhanced_caption",
            "aiHasEnhancedCaption",
        ]),
    );
    const hasVectorFlag = toBoolish(
        getFirstPresent(asset, [
            "has_ai_vector",
            "hasAiVector",
            "has_vector_embedding",
            "hasVectorEmbedding",
            "vector_indexed",
            "vectorIndexed",
        ]),
    );
    const hasAiInfoFlag = toBoolish(
        getFirstPresent(asset, ["has_ai_info", "hasAiInfo", "ai_indexed", "aiIndexed"]),
    );

    const hasAutoTags =
        hasAutoTagsFlag === true || (hasAutoTagsFlag === null && hasStructuredData(autoTagsValue));
    const hasEnhancedPrompt =
        hasEnhancedPromptFlag === true ||
        (hasEnhancedPromptFlag === null && hasNonEmptyText(enhancedPromptValue));
    const hasVectorIndexed = hasVectorFlag === true || hasAiInfoFlag === true;
    const hasAiInfo =
        hasAiInfoFlag === true || hasAutoTags || hasEnhancedPrompt || hasVectorIndexed;

    return { hasAiInfo, hasAutoTags, hasEnhancedPrompt, hasVectorIndexed };
}

/**
 * Create workflow status dot (inline with filename)
 * States:
 * - success: complete metadata
 * - warning: partial metadata
 * - error: no metadata
 * - pending/info: enrichment in progress or not parsed yet
 */
export function createWorkflowDot(asset: Record<string, any> | null | undefined): HTMLElement {
    const dot = document.createElement("span");
    dot.className = "mjr-workflow-dot mjr-asset-status-dot";

    const hasWorkflow = toBoolish(asset?.has_workflow ?? asset?.hasWorkflow);
    const hasGen = toBoolish(asset?.has_generation_data ?? asset?.hasGenerationData);
    const enrichment = getRuntimeEnrichmentState();
    const enrichmentQueue = enrichment.queueLength;
    const enrichmentActive = enrichment.active || enrichmentQueue > 0;

    let title = "Pending: parsing metadata...";

    const anyTrue = hasWorkflow === true || hasGen === true;
    const anyFalse = hasWorkflow === false || hasGen === false;
    const anyUnknown = hasWorkflow === null || hasGen === null;

    if (hasWorkflow === true && hasGen === true) {
        title = "Complete: workflow + generation data detected";
    } else if (anyTrue) {
        title =
            hasWorkflow === true
                ? "Partial: workflow only (generation data missing)"
                : "Partial: generation data only (workflow missing)";
    } else if (anyFalse && !anyTrue && !anyUnknown) {
        title = "None: no workflow or generation data found";
    } else if (anyUnknown) {
        title = "Pending: metadata not parsed yet";
    }

    let status = anyUnknown
        ? "pending"
        : hasWorkflow === true && hasGen === true
          ? "success"
          : anyTrue
            ? "warning"
            : "error";
    if (enrichmentActive && status !== "success") {
        status = "pending";
        title =
            enrichmentQueue > 0
                ? `Pending: database metadata enrichment in progress (${enrichmentQueue} queued)`
                : "Pending: database metadata enrichment in progress";
    }
    applyAssetStatusDotState(dot, status, title, { asset });
    const ai = detectAiInfo(asset);
    if (ai.hasAiInfo) {
        const aiBits = [];
        if (ai.hasVectorIndexed) aiBits.push("vector indexed");
        if (ai.hasAutoTags) aiBits.push("AI tag suggestions");
        if (ai.hasEnhancedPrompt) aiBits.push("enhanced prompt");

        dot.textContent = "";
        const icon = document.createElement("i");
        icon.className = "pi pi-sparkles";
        icon.setAttribute("aria-hidden", "true");
        icon.style.fontSize = "11px";
        icon.style.lineHeight = "1";
        dot.appendChild(icon);

        try {
            dot.dataset.mjrAi = "1";
        } catch (e: any) {
            console.debug?.(e);
        }
        dot.title = `${title}\nAI: ${aiBits.length ? aiBits.join(", ") : "indexed"}\nClick to rescan this file`;
    } else {
        try {
            dot.dataset.mjrAi = "0";
        } catch (e: any) {
            console.debug?.(e);
        }
        dot.textContent = "\u25CF";
        dot.title = `${title}\nClick to rescan this file`;
    }

    return dot;
}

export function applyAssetStatusDotState(dot: HTMLElement | null, state: string, title = "", context: Record<string, any> = {}): void {
    if (!dot) return;
    const s = String(state || "").toLowerCase();
    const color = resolveAssetStatusDotColor(s, { dot, ...(context || {}) });

    try {
        dot.dataset.mjrStatus = s || "neutral";
    } catch (e: any) {
        console.debug?.(e);
    }
    dot.style.cssText = `
        color: ${color};
        margin-left: 4px;
        font-size: 12px;
        line-height: 1;
        display: inline-flex;
        align-items: center;
        justify-content: center;
        cursor: pointer;
        transition: color 0.25s ease, opacity 0.25s ease;
    `;
    if (title) {
        try {
            dot.title = String(title);
        } catch (e: any) {
            console.debug?.(e);
        }
    }
}

/**
 * Create rating badge (stars) - Top right position
 */
export function createRatingBadge(rating: number | null | undefined): HTMLElement | null {
    const ratingValue = Math.max(0, Math.min(5, Number(rating) || 0));
    if (ratingValue <= 0) return null;

    const badge = document.createElement("div");
    badge.className = "mjr-rating-badge";
    badge.title = `Rating: ${ratingValue} star${ratingValue > 1 ? "s" : ""}`;
    badge.style.cssText = `
        position: absolute;
        top: 6px;
        right: 6px;
        background: rgba(0, 0, 0, 0.55);
        border: 1px solid rgba(255, 255, 255, 0.12);
        padding: 2px 6px;
        border-radius: 6px;
        font-size: 13px;
        letter-spacing: 1px;
        display: inline-flex;
        align-items: center;
        justify-content: center;
        pointer-events: none;
        z-index: 10;
        text-shadow: 0 2px 6px rgba(0,0,0,0.6);
        box-shadow: 0 6px 18px rgba(0,0,0,0.25);
    `;

    for (let i = 1; i <= ratingValue; i++) {
        const star = document.createElement("span");
        star.textContent = "\u2605";
        star.style.color = "var(--mjr-rating-color, var(--mjr-star-active, #FFD45A))";
        star.style.marginRight = i < ratingValue ? "2px" : "0";
        badge.appendChild(star);
    }

    return badge;
}

/**
 * Create tags badge - Bottom left position
 */
function _normalizeBadgeTags(tags: any) {
    if (Array.isArray(tags)) {
        return tags.map((tag: any) => String(tag ?? "").trim()).filter(Boolean);
    }
    if (typeof tags === "string") {
        const raw = tags.trim();
        if (!raw) return [];
        try {
            const parsed = JSON.parse(raw);
            if (Array.isArray(parsed)) {
                return parsed.map((tag: any) => String(tag ?? "").trim()).filter(Boolean);
            }
        } catch {}
        return raw
            .split(",")
            .map((tag: any) => tag.trim())
            .filter(Boolean);
    }
    return [];
}

/**
 * Returns a CSS color string for a given generation time in milliseconds.
 * Thresholds: green < 10s, light-green < 30s, yellow < 60s, orange >= 60s.
 */
export function genTimeColor(ms: any) {
    const secs = Number(ms) / 1000;
    if (secs >= 60) return "#FF9800";
    if (secs >= 30) return "#FFC107";
    if (secs >= 10) return "#8BC34A";
    return "#4CAF50";
}

/**
 * Format generation time for display.
 * Shows seconds (e.g. "45.2s") when < 60s, minutes (e.g. "3.6m") when >= 60s.
 * Returns { text, title } for badge display.
 */
export function formatGenTime(ms: any) {
    const totalSecs = ms / 1000;
    if (totalSecs >= 60) {
        const mins = (totalSecs / 60).toFixed(1);
        return {
            text: `${mins}m`,
            title: `Generation time: ${mins} minutes (${totalSecs.toFixed(1)}s)`,
        };
    }
    const secs = totalSecs.toFixed(1);
    return {
        text: `${secs}s`,
        title: `Generation time: ${secs} seconds`,
    };
}

/**
 * Normalize generation time into milliseconds.
 * Accepts plain numbers, numeric strings, and unit-suffixed strings like "8.2s" or "8200ms".
 * Returns 0 when invalid, non-positive, or outside sanity bounds.
 */
export function normalizeGenerationTimeMs(value: any, { maxMs = 86_400_000 } = {}) {
    let ms;
    if (value == null) return 0;
    if (typeof value === "string") {
        const raw = value.trim().toLowerCase();
        if (!raw) return 0;
        const secMatch = raw.match(/^(-?\d+(?:[.,]\d+)?)\s*(s|sec|secs|second|seconds)$/i);
        if (secMatch) {
            ms = Number(secMatch[1].replace(",", ".")) * 1000;
        } else {
            const msMatch = raw.match(
                /^(-?\d+(?:[.,]\d+)?)\s*(ms|msec|millisecond|milliseconds)$/i,
            );
            if (msMatch) {
                ms = Number(msMatch[1].replace(",", "."));
            } else {
                ms = Number(raw.replace(",", "."));
            }
        }
    } else {
        ms = Number(value);
    }

    if (!Number.isFinite(ms) || ms <= 0 || ms >= Number(maxMs)) return 0;
    return ms;
}

/**
 * Create generation-time badge (overlaid on thumbnail, bottom-right).
 * Returns null when genTimeMs is 0 or invalid (> 24h sanity limit).
 */
export function createGenTimeBadge(genTimeMs: any) {
    const ms = normalizeGenerationTimeMs(genTimeMs);
    if (!ms) return null;

    const badge = document.createElement("div");
    badge.className = "mjr-gentime-badge";
    const fmt = formatGenTime(ms);
    badge.textContent = fmt.text;
    badge.title = fmt.title;
    badge.style.cssText = `
        position: absolute;
        bottom: 6px;
        right: 6px;
        padding: 2px 6px;
        border-radius: 4px;
        font-size: 10px;
        font-weight: 700;
        background: rgba(0,0,0,0.55);
        border: 1px solid rgba(255,255,255,0.12);
        color: ${genTimeColor(ms)};
        pointer-events: none;
        z-index: 10;
        box-shadow: 0 2px 4px rgba(0,0,0,0.3);
    `;
    return badge;
}

export function createTagsBadge(tags: string[] | null | undefined): HTMLElement {
    const badge = document.createElement("div");
    badge.className = "mjr-tags-badge";
    const normalizedTags = _normalizeBadgeTags(tags);

    if (normalizedTags.length === 0) {
        badge.style.display = "none";
        return badge;
    }

    badge.textContent = normalizedTags.join(", ");
    badge.title = `Tags: ${normalizedTags.join(", ")}`;
    badge.style.cssText = `
        position: absolute;
        bottom: 6px;
        left: 6px;
        padding: 3px 6px;
        border-radius: 4px;
        background: rgba(0,0,0,0.8);
        color: var(--mjr-tag-color, #90CAF9);
        font-size: 9px;
        max-width: 80%;
        overflow: hidden;
        text-overflow: ellipsis;
        white-space: nowrap;
        pointer-events: none;
        z-index: 10;
        box-shadow: 0 2px 4px rgba(0,0,0,0.3);
    `;

    return badge;
}
