import { mkdir, readFile, writeFile } from "node:fs/promises";
import { dirname } from "node:path";

type ManifestFileShape = {
    version: 1;
    updatedAt: string;
    enabled: Record<string, boolean>;
};

export type ExtensionManifestSnapshot = {
    updatedAt: string;
    enabled: Record<string, boolean>;
};

const EMPTY_MANIFEST: ManifestFileShape = {
    version: 1,
    updatedAt: new Date(0).toISOString(),
    enabled: {}
};

export class ExtensionManifestStore {
    private manifest: ManifestFileShape = { ...EMPTY_MANIFEST, enabled: {} };

    public constructor(private readonly filePath: string) {}

    public async load(): Promise<ExtensionManifestSnapshot> {
        try {
            const raw = await readFile(this.filePath, "utf8");
            const parsed = JSON.parse(raw) as Partial<ManifestFileShape>;
            this.manifest = {
                version: 1,
                updatedAt:
                    typeof parsed.updatedAt === "string" && parsed.updatedAt
                        ? parsed.updatedAt
                        : new Date().toISOString(),
                enabled:
                    parsed.enabled && typeof parsed.enabled === "object"
                        ? { ...parsed.enabled }
                        : {}
            };
        } catch {
            this.manifest = {
                version: 1,
                updatedAt: new Date().toISOString(),
                enabled: {}
            };
            await this.save();
        }

        return this.snapshot();
    }

    public snapshot(): ExtensionManifestSnapshot {
        return {
            updatedAt: this.manifest.updatedAt,
            enabled: { ...this.manifest.enabled }
        };
    }

    public isEnabled(extensionId: string, fallback = true): boolean {
        const value = this.manifest.enabled[extensionId];
        return typeof value === "boolean" ? value : fallback;
    }

    public async setEnabled(extensionId: string, enabled: boolean): Promise<void> {
        this.manifest.enabled[extensionId] = enabled;
        this.manifest.updatedAt = new Date().toISOString();
        await this.save();
    }

    private async save(): Promise<void> {
        await mkdir(dirname(this.filePath), { recursive: true });
        await writeFile(this.filePath, JSON.stringify(this.manifest, null, 2), "utf8");
    }
}
