import { existsSync, mkdirSync, readFileSync, writeFileSync } from "node:fs";
import { join } from "node:path";

import { getAppDataDir } from "../db/connection";
import type { OptimizedArticle, QaReport } from "../domain/types";
import { getAppCloudflareEnv } from "../runtime/cloudflare";
import {
  renderOptimizedDocx,
  renderOptimizedMarkdown,
  renderQaReportJson,
} from "./exporter";

const CONTENT_TYPES: Record<string, string> = {
  "optimized.md": "text/markdown; charset=utf-8",
  "optimized.docx":
    "application/vnd.openxmlformats-officedocument.wordprocessingml.document",
  "qa_report.json": "application/json; charset=utf-8",
};

export interface WriteJobExportsInput {
  jobId: string;
  article: OptimizedArticle;
  qaReport: QaReport;
}

export interface ExportStore {
  writeJobExports(input: WriteJobExportsInput): Promise<Record<string, string>>;
  readJobExport(jobId: string, fileName: string): Promise<Response | null>;
}

export function createLocalExportStore(dataDir = getAppDataDir()): ExportStore {
  return {
    async writeJobExports({ jobId, article, qaReport }) {
      const exportDir = join(dataDir, "exports", jobId);
      mkdirSync(exportDir, { recursive: true });

      const markdown = join(exportDir, "optimized.md");
      const docx = join(exportDir, "optimized.docx");
      const qaJson = join(exportDir, "qa_report.json");

      writeFileSync(markdown, renderOptimizedMarkdown(article), "utf8");
      writeFileSync(qaJson, renderQaReportJson(qaReport), "utf8");
      writeFileSync(docx, await renderOptimizedDocx(article));

      return { markdown, docx, qaJson };
    },
    async readJobExport(jobId, fileName) {
      const contentType = CONTENT_TYPES[fileName];
      if (!contentType) return null;

      const path = join(dataDir, "exports", jobId, fileName);
      if (!existsSync(path)) return null;

      return new Response(readFileSync(path), {
        headers: {
          "content-type": contentType,
          "content-disposition": `attachment; filename="${fileName}"`,
        },
      });
    },
  };
}

export function createR2ExportStore(bucket: R2Bucket): ExportStore {
  return {
    async writeJobExports({ jobId, article, qaReport }) {
      const prefix = `exports/${jobId}`;
      const markdownKey = `${prefix}/optimized.md`;
      const docxKey = `${prefix}/optimized.docx`;
      const qaJsonKey = `${prefix}/qa_report.json`;

      await bucket.put(markdownKey, renderOptimizedMarkdown(article), {
        httpMetadata: { contentType: CONTENT_TYPES["optimized.md"] },
      });
      await bucket.put(qaJsonKey, renderQaReportJson(qaReport), {
        httpMetadata: { contentType: CONTENT_TYPES["qa_report.json"] },
      });
      await bucket.put(docxKey, await renderOptimizedDocx(article), {
        httpMetadata: { contentType: CONTENT_TYPES["optimized.docx"] },
      });

      return {
        markdown: `r2://${markdownKey}`,
        docx: `r2://${docxKey}`,
        qaJson: `r2://${qaJsonKey}`,
      };
    },
    async readJobExport(jobId, fileName) {
      const contentType = CONTENT_TYPES[fileName];
      if (!contentType) return null;

      const object = await bucket.get(`exports/${jobId}/${fileName}`);
      if (!object) return null;

      return new Response(object.body, {
        headers: {
          "content-type": object.httpMetadata?.contentType ?? contentType,
          "content-disposition": `attachment; filename="${fileName}"`,
        },
      });
    },
  };
}

export function getExportStoreFromRuntime(): ExportStore {
  if (process.env.APP_RUNTIME === "cloudflare") {
    const env = getAppCloudflareEnv();
    if (!env?.EXPORT_BUCKET) {
      throw new Error("Cloudflare R2 binding EXPORT_BUCKET is required");
    }
    return createR2ExportStore(env.EXPORT_BUCKET);
  }

  return createLocalExportStore();
}
