import type { Page } from "@/lib/store";
import { useSettingsStore } from "@/lib/settings-store";

const MAX_SNAPSHOTS_PER_PAGE = 30;
const RETENTION_DAYS = 30;
const MIN_SNAPSHOT_INTERVAL_MS = 15_000;
const HISTORY_KEY_PREFIX = "noteai:history:";

export type PageSnapshot = {
    title: string;
    content: string;
    timestamp: string;
};

function getKey(pageId: string): string {
    return `${HISTORY_KEY_PREFIX}${pageId}`;
}

function canUseStorage(): boolean {
    return typeof window !== "undefined" && typeof localStorage !== "undefined";
}

function isSnapshot(item: unknown): item is PageSnapshot {
    return (
        !!item &&
        typeof item === "object" &&
        typeof (item as PageSnapshot).title === "string" &&
        typeof (item as PageSnapshot).content === "string" &&
        typeof (item as PageSnapshot).timestamp === "string"
    );
}

function clampInt(value: number, fallback: number, min: number, max: number): number {
    if (!Number.isFinite(value)) return fallback;
    return Math.min(max, Math.max(min, Math.round(value)));
}

function getRetentionConfig() {
    const settings = useSettingsStore.getState().localHistory;
    return {
        maxSnapshotsPerPage: clampInt(settings?.maxSnapshotsPerPage ?? MAX_SNAPSHOTS_PER_PAGE, MAX_SNAPSHOTS_PER_PAGE, 5, 200),
        retentionDays: clampInt(settings?.retentionDays ?? RETENTION_DAYS, RETENTION_DAYS, 1, 365),
    };
}

function pruneSnapshots(snapshots: PageSnapshot[]): PageSnapshot[] {
    const { maxSnapshotsPerPage, retentionDays } = getRetentionConfig();
    const minTimestamp = Date.now() - retentionDays * 24 * 60 * 60 * 1000;

    return snapshots
        .filter((item) => {
            const ts = new Date(item.timestamp).getTime();
            if (Number.isNaN(ts)) return false;
            return ts >= minTimestamp;
        })
        .slice(0, maxSnapshotsPerPage);
}

export function getPageHistory(pageId: string): PageSnapshot[] {
    if (!canUseStorage()) return [];

    try {
        const raw = localStorage.getItem(getKey(pageId));
        if (!raw) return [];

        const parsed = JSON.parse(raw);
        if (!Array.isArray(parsed)) return [];

        const normalized = parsed.filter(isSnapshot);
        const pruned = pruneSnapshots(normalized);

        if (pruned.length !== normalized.length) {
            localStorage.setItem(getKey(pageId), JSON.stringify(pruned));
        }

        return pruned;
    } catch {
        return [];
    }
}

export function capturePageSnapshot(page: Pick<Page, "id" | "title" | "content">): void {
    if (!canUseStorage()) return;

    const history = getPageHistory(page.id);
    const latest = history[0];

    if (latest && latest.title === page.title && latest.content === page.content) {
        return;
    }

    if (latest) {
        const gap = Date.now() - new Date(latest.timestamp).getTime();
        if (!Number.isNaN(gap) && gap < MIN_SNAPSHOT_INTERVAL_MS) {
            return;
        }
    }

    const next: PageSnapshot[] = [
        {
            title: page.title || "无标题",
            content: page.content || "",
            timestamp: new Date().toISOString(),
        },
        ...history,
    ];

    try {
        localStorage.setItem(getKey(page.id), JSON.stringify(pruneSnapshots(next)));
    } catch {
        // Ignore storage errors.
    }
}

export function cleanupAllPageHistories(): { touched: number } {
    if (!canUseStorage()) return { touched: 0 };

    const targets: string[] = [];
    for (let i = 0; i < localStorage.length; i += 1) {
        const key = localStorage.key(i);
        if (!key || !key.startsWith(HISTORY_KEY_PREFIX)) continue;
        targets.push(key);
    }

    let touched = 0;
    for (const key of targets) {
        try {
            const raw = localStorage.getItem(key);
            if (!raw) continue;

            const parsed = JSON.parse(raw);
            if (!Array.isArray(parsed)) {
                localStorage.removeItem(key);
                touched += 1;
                continue;
            }

            const normalized = parsed.filter(isSnapshot);
            const pruned = pruneSnapshots(normalized);
            if (pruned.length === 0) {
                localStorage.removeItem(key);
            } else {
                localStorage.setItem(key, JSON.stringify(pruned));
            }

            touched += 1;
        } catch {
            localStorage.removeItem(key);
            touched += 1;
        }
    }

    return { touched };
}

export function estimateAllPageHistoriesUsage(): {
    keys: number;
    snapshots: number;
    bytes: number;
} {
    if (!canUseStorage()) return { keys: 0, snapshots: 0, bytes: 0 };

    let keys = 0;
    let snapshots = 0;
    let bytes = 0;

    for (let i = 0; i < localStorage.length; i += 1) {
        const key = localStorage.key(i);
        if (!key || !key.startsWith(HISTORY_KEY_PREFIX)) continue;

        const raw = localStorage.getItem(key);
        if (!raw) continue;
        keys += 1;
        bytes += raw.length * 2;
        try {
            const parsed = JSON.parse(raw);
            if (Array.isArray(parsed)) {
                snapshots += parsed.filter(isSnapshot).length;
            }
        } catch {
            // ignore parse failures here
        }
    }

    return { keys, snapshots, bytes };
}

export function trimAllPageHistoriesToRecent(limitPerPage: number): {
    touched: number;
    removedSnapshots: number;
} {
    if (!canUseStorage()) return { touched: 0, removedSnapshots: 0 };

    const limit = clampInt(limitPerPage, 10, 1, 200);
    const targets: string[] = [];
    for (let i = 0; i < localStorage.length; i += 1) {
        const key = localStorage.key(i);
        if (!key || !key.startsWith(HISTORY_KEY_PREFIX)) continue;
        targets.push(key);
    }

    let touched = 0;
    let removedSnapshots = 0;

    for (const key of targets) {
        try {
            const raw = localStorage.getItem(key);
            if (!raw) continue;
            const parsed = JSON.parse(raw);
            if (!Array.isArray(parsed)) {
                localStorage.removeItem(key);
                touched += 1;
                continue;
            }
            const normalized = parsed.filter(isSnapshot);
            const prunedByPolicy = pruneSnapshots(normalized);
            const next = prunedByPolicy.slice(0, limit);
            removedSnapshots += Math.max(0, normalized.length - next.length);
            if (next.length === 0) {
                localStorage.removeItem(key);
            } else {
                localStorage.setItem(key, JSON.stringify(next));
            }
            touched += 1;
        } catch {
            localStorage.removeItem(key);
            touched += 1;
        }
    }

    return { touched, removedSnapshots };
}
