import { ExtensionAPI } from "@mariozechner/pi-coding-agent";
import { applyExtensionDefaults } from "./themeMap.ts";
import { 
  Box, Text, Markdown, Container, Spacer, 
  matchesKey, Key, truncateToWidth, MarkdownTheme 
} from "@mariozechner/pi-tui";
import { DynamicBorder, getMarkdownTheme as getPiMdTheme } from "@mariozechner/pi-coding-agent";

// Minimal shim for timestamp handling if not directly in Message objects
function formatTime(date: Date): string {
    return date.toLocaleTimeString([], { hour: '2-digit', minute: '2-digit', second: '2-digit' });
}

function getElapsedTime(start: Date, end: Date): string {
    const diffMs = end.getTime() - start.getTime();
    const diffSec = Math.floor(diffMs / 1000);
    if (diffSec < 60) return `${diffSec}s`;
    const diffMin = Math.floor(diffSec / 60);
    return `${diffMin}m ${diffSec % 60}s`;
}

interface HistoryItem {
    type: 'user' | 'assistant' | 'tool';
    title: string;
    content: string;
    timestamp: Date;
    elapsed?: string;
}

class SessionReplayUI {
    private selectedIndex = 0;
    private expandedIndex: number | null = null;
    private scrollOffset = 0;
    
    constructor(
        private items: HistoryItem[],
        private onDone: () => void
    ) {
        // Start selected at the bottom (most recent)
        this.selectedIndex = Math.max(0, items.length - 1);
        this.ensureVisible(20); // rough height estimate
    }

    handleInput(data: string, tui: any): void {
        if (matchesKey(data, Key.up)) {
            this.selectedIndex = Math.max(0, this.selectedIndex - 1);
        } else if (matchesKey(data, Key.down)) {
            this.selectedIndex = Math.min(this.items.length - 1, this.selectedIndex + 1);
        } else if (matchesKey(data, Key.enter)) {
            this.expandedIndex = this.expandedIndex === this.selectedIndex ? null : this.selectedIndex;
        } else if (matchesKey(data, Key.escape)) {
            this.onDone();
            return;
        }
        tui.requestRender();
    }

    private ensureVisible(height: number) {
        // Simple scroll window logic
        const pageSize = Math.floor(height / 3); // Approx items per page
        if (this.selectedIndex < this.scrollOffset) {
            this.scrollOffset = this.selectedIndex;
        } else if (this.selectedIndex >= this.scrollOffset + pageSize) {
            this.scrollOffset = this.selectedIndex - pageSize + 1;
        }
    }

    render(width: number, height: number, theme: any): string[] {
        this.ensureVisible(height);
        
        const container = new Container();
        const mdTheme = getPiMdTheme();

        // Header
        container.addChild(new DynamicBorder((s: string) => theme.fg("accent", s)));
        container.addChild(new Text(`${theme.fg("accent", theme.bold(" SESSION REPLAY"))} ${theme.fg("dim", "|")} ${theme.fg("success", this.items.length.toString())} entries`, 1, 0));
        container.addChild(new Spacer(1));

        // Calculate visible range
        const visibleItems = this.items.slice(this.scrollOffset);

        visibleItems.forEach((item, idx) => {
            const absoluteIndex = idx + this.scrollOffset;
            const isSelected = absoluteIndex === this.selectedIndex;
            const isExpanded = absoluteIndex === this.expandedIndex;
            
            const cardBox = new Box(1, 0, (s) => isSelected ? theme.bg("selectedBg", s) : s);
            
            // Icon and Title
            let icon = "○";
            let color = "dim";
            if (item.type === 'user') { icon = "👤"; color = "success"; }
            else if (item.type === 'assistant') { icon = "🤖"; color = "accent"; }
            else if (item.type === 'tool') { icon = "🛠️"; color = "warning"; }

            const timeStr = theme.fg("success", `[${formatTime(item.timestamp)}]`);
            const elapsedStr = item.elapsed ? theme.fg("dim", ` (+${item.elapsed})`) : "";
            
            const titleLine = `${theme.fg(color, icon)} ${theme.bold(item.title)} ${timeStr}${elapsedStr}`;
            cardBox.addChild(new Text(titleLine, 0, 0));

            if (isExpanded) {
                cardBox.addChild(new Spacer(1));
                cardBox.addChild(new Markdown(item.content, 2, 0, mdTheme));
            } else {
                // Truncated preview
                const preview = item.content.replace(/\n/g, ' ').substring(0, width - 10);
                cardBox.addChild(new Text(theme.fg("dim", "  " + preview + "..."), 0, 0));
            }

            container.addChild(cardBox);
            // Don't add too many spacers if we have many items
            if (visibleItems.length < 15) container.addChild(new Spacer(1));
        });

        // Footer
        container.addChild(new Spacer(1));
        container.addChild(new Text(theme.fg("dim", " ↑/↓ Navigate • Enter Expand • Esc Close"), 1, 0));
        container.addChild(new DynamicBorder((s: string) => theme.fg("accent", s)));

        return container.render(width);
    }
}

function extractContent(entry: any): string {
    const msg = entry.message;
    if (!msg) return "";
    const content = msg.content;
    if (!content) return "";
    if (typeof content === "string") return content;
    if (Array.isArray(content)) {
        return content
            .map((c: any) => {
                if (c.type === "text") return c.text || "";
                if (c.type === "toolCall") return `Tool: ${c.name}(${JSON.stringify(c.arguments).slice(0, 200)})`;
                return "";
            })
            .filter(Boolean)
            .join("\n");
    }
    return JSON.stringify(content).slice(0, 500);
}

export default function(pi: ExtensionAPI) {
    pi.registerCommand("replay", {
        description: "Show a scrollable timeline of the current session",
        handler: async (args, ctx) => {
            const branch = ctx.sessionManager.getBranch();
            const items: HistoryItem[] = [];

            let prevTime: Date | null = null;

            for (const entry of branch) {
                if (entry.type !== "message") continue;
                const msg = entry.message;
                if (!msg) continue;

                const ts = msg.timestamp ? new Date(msg.timestamp) : new Date();
                const elapsed = prevTime ? getElapsedTime(prevTime, ts) : undefined;
                prevTime = ts;

                const role = msg.role;
                const text = extractContent(entry);
                if (!text) continue;

                if (role === "user") {
                    items.push({
                        type: "user",
                        title: "User Prompt",
                        content: text,
                        timestamp: ts,
                        elapsed,
                    });
                } else if (role === "assistant") {
                    items.push({
                        type: "assistant",
                        title: "Assistant",
                        content: text,
                        timestamp: ts,
                        elapsed,
                    });
                } else if (role === "toolResult") {
                    const toolName = (msg as any).toolName || "tool";
                    items.push({
                        type: "tool",
                        title: `Tool: ${toolName}`,
                        content: text,
                        timestamp: ts,
                        elapsed,
                    });
                }
            }

            if (items.length === 0) {
                ctx.ui.notify("No session history found.", "warning");
                return;
            }

            await ctx.ui.custom((tui, theme, kb, done) => {
                const component = new SessionReplayUI(items, () => done(undefined));
                return {
                    render: (w) => component.render(w, 30, theme),
                    handleInput: (data) => component.handleInput(data, tui),
                    invalidate: () => {},
                };
            }, {
                overlay: true,
                overlayOptions: { width: "80%", anchor: "center" },
            });
        },
    });

    pi.on("session_start", async (_event, ctx) => {
        applyExtensionDefaults(import.meta.url, ctx);
    });
}
