import { promises as fs } from "fs";
import path from "path";
import { getDbPath, getPackagedDefaultDbPath } from "@/lib/app-paths";
import {
  AuditEvent,
  KnowledgeDocument,
  LicenseConfig,
  OperatorPlan,
  PinterestAccount,
  PinterestAutomationTask,
  PinterestBoard,
  PinterestLead,
  PinterestOAuthState,
  PinterestOAuthToken,
  PinterestPinDraft,
  PinterestTrendResearch,
  RiskLimits,
} from "@/lib/types";

export type Database = {
  account: PinterestAccount;
  oauth: {
    state: PinterestOAuthState;
    token: PinterestOAuthToken;
  };
  boards: PinterestBoard[];
  pinDrafts: PinterestPinDraft[];
  operatorPlans: OperatorPlan[];
  trendResearch: PinterestTrendResearch[];
  leads: PinterestLead[];
  knowledgeDocuments: KnowledgeDocument[];
  tasks: PinterestAutomationTask[];
  auditLogs: AuditEvent[];
  license: LicenseConfig;
  riskLimits: RiskLimits;
};

const dbPath = getDbPath();
let writeQueue = Promise.resolve();

function nowIso() {
  return new Date().toISOString();
}

function defaultRiskLimits(): RiskLimits {
  return {
    dailyTrendResearches: 20,
    dailyPinPublishes: 20,
    dailyBoardCreates: 5,
    dailyApiWrites: 80,
    requireApprovalForPublish: true,
    requireApprovalForFollow: true,
    requireApprovalForComment: true,
    requireApprovalForMessage: true,
  };
}

function defaultLicense(): LicenseConfig {
  const now = new Date();
  const expires = new Date(now.getTime() + 14 * 24 * 60 * 60 * 1000);
  return {
    licenseId: "trial-local",
    customerName: "试用客户",
    plan: "growth",
    status: "trial",
    purchaseType: "trial",
    issuedAt: now.toISOString(),
    expiresAt: expires.toISOString(),
    seats: 1,
    pinterestAccounts: 1,
    verificationStatus: "unverified",
    remoteServerUrl: "",
    remoteLicenseKey: "",
    heartbeatStatus: "not_configured",
    graceHours: 5,
  };
}

const seed: Database = {
  account: {
    id: "acct-local",
    accountName: "未连接 Pinterest",
    businessAccount: false,
    scopes: [],
    tokenStatus: "missing",
    updatedAt: nowIso(),
  },
  oauth: {
    state: {
      scopes: [],
    },
    token: {},
  },
  boards: [
    {
      id: "board-demo-1",
      name: "Product Ideas",
      description: "用于承接产品 Pin 和内容灵感的示例图板。",
      privacy: "PUBLIC",
      pinCount: 0,
      createdAt: nowIso(),
      updatedAt: nowIso(),
    },
  ],
  pinDrafts: [
    {
      id: "pin-demo-1",
      boardId: "board-demo-1",
      title: "Seasonal product inspiration",
      description: "用趋势关键词和真实产品卖点生成的 Pin 草稿，等待人工确认。",
      link: "https://example.com/product",
      mediaType: "image",
      keywords: ["seasonal", "product", "inspiration"],
      status: "pending_review",
      createdAt: nowIso(),
      updatedAt: nowIso(),
    },
  ],
  operatorPlans: [],
  trendResearch: [],
  leads: [],
  knowledgeDocuments: [],
  tasks: [],
  auditLogs: [],
  license: defaultLicense(),
  riskLimits: defaultRiskLimits(),
};

export async function readDb(): Promise<Database> {
  try {
    const raw = await fs.readFile(dbPath, "utf8");
    const parsed = JSON.parse(raw) as Partial<Database>;
    return normalizeDb(parsed);
  } catch (error: any) {
    if (error?.code !== "ENOENT") throw error;
    const packaged = await readPackagedDefaultDb();
    if (packaged) {
      await fs.mkdir(path.dirname(dbPath), { recursive: true });
      await fs.writeFile(dbPath, JSON.stringify(packaged, null, 2));
      return packaged;
    }
    await fs.mkdir(path.dirname(dbPath), { recursive: true });
    await fs.writeFile(dbPath, JSON.stringify(seed, null, 2));
    return seed;
  }
}

export async function writeDb(db: Database) {
  writeQueue = writeQueue.then(async () => {
    await fs.mkdir(path.dirname(dbPath), { recursive: true });
    const tmpPath = `${dbPath}.${process.pid}.${Date.now()}.tmp`;
    await fs.writeFile(tmpPath, JSON.stringify(db, null, 2));
    await fs.rename(tmpPath, dbPath);
  });
  await writeQueue;
}

export function createId(prefix: string) {
  return `${prefix}-${Date.now()}-${Math.random().toString(36).slice(2, 7)}`;
}

export function addAudit(db: Database, event: Omit<AuditEvent, "id" | "createdAt">) {
  db.auditLogs.unshift({
    id: createId("audit"),
    createdAt: nowIso(),
    ...event,
  });
}

function normalizeDb(value: Partial<Database>): Database {
  return {
    account: {
      ...seed.account,
      ...(value.account || {}),
      scopes: value.account?.scopes || [],
      updatedAt: value.account?.updatedAt || nowIso(),
    },
    oauth: {
      state: {
        scopes: value.oauth?.state?.scopes || [],
        state: value.oauth?.state?.state,
        redirectUri: value.oauth?.state?.redirectUri,
        createdAt: value.oauth?.state?.createdAt,
      },
      token: {
        ...(value.oauth?.token || {}),
      },
    },
    boards: value.boards || [],
    pinDrafts: value.pinDrafts || [],
    operatorPlans: value.operatorPlans || [],
    trendResearch: value.trendResearch || [],
    leads: value.leads || [],
    knowledgeDocuments: value.knowledgeDocuments || [],
    tasks: value.tasks || [],
    auditLogs: value.auditLogs || [],
    license: normalizeLicense(value.license),
    riskLimits: {
      ...defaultRiskLimits(),
      ...(value.riskLimits || {}),
    },
  };
}

function normalizeLicense(value: unknown): LicenseConfig {
  const raw = value && typeof value === "object" && !Array.isArray(value)
    ? value as Partial<LicenseConfig>
    : {};
  const fallback = defaultLicense();
  const plan = raw.plan === "starter" || raw.plan === "growth" || raw.plan === "pro" || raw.plan === "enterprise"
    ? raw.plan
    : fallback.plan;
  const status = raw.status === "active" || raw.status === "trial" || raw.status === "expired" || raw.status === "suspended"
    ? raw.status
    : fallback.status;
  return {
    ...fallback,
    ...raw,
    plan,
    status,
    customerName: raw.customerName || fallback.customerName,
    issuedAt: raw.issuedAt || fallback.issuedAt,
    expiresAt: raw.expiresAt || fallback.expiresAt,
    seats: normalizePositiveInt(raw.seats, fallback.seats),
    pinterestAccounts: normalizePositiveInt(raw.pinterestAccounts, fallback.pinterestAccounts),
    graceHours: normalizePositiveInt(raw.graceHours, fallback.graceHours || 5),
  };
}

async function readPackagedDefaultDb() {
  try {
    const raw = await fs.readFile(getPackagedDefaultDbPath(), "utf8");
    return normalizeDb(JSON.parse(raw) as Partial<Database>);
  } catch {
    return null;
  }
}

function normalizePositiveInt(value: unknown, fallback: number) {
  const parsed = Number(value);
  if (!Number.isFinite(parsed) || parsed <= 0) return fallback;
  return Math.floor(parsed);
}
