/**
 * 업무 체크리스트: PostgreSQL 또는 data/meeting-ai-checklist.json 폴백
 */
const path = require("path");
const fs = require("fs/promises");
const { v4: uuidv4 } = require("uuid");

const CHECKLIST_FILE = path.join(__dirname, "..", "data", "meeting-ai-checklist.json");

let writeChain = Promise.resolve();

function withFileLock(fn) {
  const p = writeChain.then(() => fn());
  writeChain = p.catch(() => {});
  return p;
}

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

async function readFileStore() {
  try {
    const raw = await fs.readFile(CHECKLIST_FILE, "utf8");
    const j = JSON.parse(raw);
    if (!j || typeof j !== "object") return { items: [] };
    if (!Array.isArray(j.items)) j.items = [];
    return j;
  } catch {
    return { items: [] };
  }
}

async function writeFileStore(data) {
  const dir = path.dirname(CHECKLIST_FILE);
  await fs.mkdir(dir, { recursive: true });
  const tmp = `${CHECKLIST_FILE}.${process.pid}.tmp`;
  await fs.writeFile(tmp, JSON.stringify(data, null, 2), "utf8");
  await fs.rename(tmp, CHECKLIST_FILE);
}

function rowToApi(row) {
  if (!row) return null;
  return {
    id: row.id,
    userEmail: row.user_email,
    meetingId: row.meeting_id || null,
    title: row.title || "",
    detail: row.detail || "",
    assignee: row.assignee || null,
    dueNote: row.due_note || null,
    completed: row.completed === true,
    completedAt: row.completed_at ? new Date(row.completed_at).toISOString() : null,
    completionNote:
      row.completion_note == null || !String(row.completion_note).trim()
        ? null
        : String(row.completion_note),
    sortOrder: Number(row.sort_order) || 0,
    source: row.source || "manual",
    createdAt: row.created_at ? new Date(row.created_at).toISOString() : nowIso(),
    updatedAt: row.updated_at ? new Date(row.updated_at).toISOString() : nowIso(),
  };
}

/**
 * @param {import("pg").Pool | null} pgPool
 * @param {string} email
 * @param {{ completed?: boolean|null, meetingId?: string|null }} [filters]
 */
async function listItems(pgPool, email, filters = {}) {
  if (pgPool) {
    const params = [email];
    let sql = `SELECT * FROM meeting_ai_checklist_items WHERE user_email = $1`;
    if (filters.completed === true) sql += ` AND completed = true`;
    else if (filters.completed === false) sql += ` AND completed = false`;
    if (filters.meetingId) {
      params.push(filters.meetingId);
      sql += ` AND meeting_id = $${params.length}::uuid`;
    }
    sql += ` ORDER BY completed ASC, sort_order ASC, updated_at DESC`;
    const r = await pgPool.query(sql, params);
    return (r.rows || []).map(rowToApi);
  }
  const data = await readFileStore();
  let items = data.items.filter((x) => x.user_email === email);
  if (filters.completed === true) items = items.filter((x) => x.completed === true);
  else if (filters.completed === false) items = items.filter((x) => !x.completed);
  if (filters.meetingId) items = items.filter((x) => x.meeting_id === filters.meetingId);
  items.sort((a, b) => {
    if (a.completed !== b.completed) return a.completed ? 1 : -1;
    return new Date(b.updated_at) - new Date(a.updated_at);
  });
  return items.map(rowToApi);
}

/**
 * @param {import("pg").Pool | null} pgPool
 */
async function insertItem(pgPool, email, fields) {
  const title = (fields.title || "").toString().trim().slice(0, 2000);
  if (!title) throw new Error("제목이 필요합니다.");
  const detail = (fields.detail || "").toString().slice(0, 8000);
  const assignee = fields.assignee != null ? String(fields.assignee).slice(0, 300) : null;
  const dueNote = fields.dueNote != null ? String(fields.dueNote).slice(0, 300) : null;
  const meetingId = fields.meetingId || null;
  const source = fields.source === "imported" ? "imported" : "manual";
  const completed = fields.completed === true;
  const sortOrder = Number.isFinite(Number(fields.sortOrder)) ? Number(fields.sortOrder) : 0;

  const completionNote =
    fields.completionNote != null && String(fields.completionNote).trim()
      ? String(fields.completionNote).slice(0, 8000)
      : null;

  if (pgPool) {
    const r = await pgPool.query(
      `INSERT INTO meeting_ai_checklist_items (
        user_email, meeting_id, title, detail, assignee, due_note, completed, completed_at, sort_order, source, completion_note
      ) VALUES ($1, $2::uuid, $3, $4, $5, $6, $7, $8, $9, $10, $11)
      RETURNING *`,
      [
        email,
        meetingId,
        title,
        detail || null,
        assignee,
        dueNote,
        completed,
        completed ? new Date() : null,
        sortOrder,
        source,
        completionNote,
      ]
    );
    return rowToApi(r.rows?.[0]);
  }
  return withFileLock(async () => {
    const data = await readFileStore();
    const t = nowIso();
    const row = {
      id: uuidv4(),
      user_email: email,
      meeting_id: meetingId,
      title,
      detail: detail || null,
      assignee,
      due_note: dueNote,
      completed,
      completed_at: completed ? t : null,
      completion_note: completionNote,
      sort_order: sortOrder,
      source,
      created_at: t,
      updated_at: t,
    };
    data.items.push(row);
    await writeFileStore(data);
    return rowToApi(row);
  });
}

/**
 * @param {import("pg").Pool | null} pgPool
 */
async function updateItem(pgPool, id, email, fields) {
  if (pgPool) {
    const cur = await pgPool.query(
      `SELECT * FROM meeting_ai_checklist_items WHERE id = $1::uuid AND user_email = $2`,
      [id, email]
    );
    if (!cur.rows?.[0]) return null;
    const row = cur.rows[0];
    const title = fields.title != null ? String(fields.title).trim().slice(0, 2000) : row.title;
    const detail =
      fields.detail !== undefined
        ? fields.detail != null && String(fields.detail).trim()
          ? String(fields.detail).slice(0, 8000)
          : null
        : row.detail;
    const assignee = fields.assignee !== undefined ? (fields.assignee ? String(fields.assignee).slice(0, 300) : null) : row.assignee;
    const dueNote = fields.dueNote !== undefined ? (fields.dueNote ? String(fields.dueNote).slice(0, 300) : null) : row.due_note;
    let completed = row.completed;
    let completedAt = row.completed_at;
    let completionNote = row.completion_note;
    if (fields.completed !== undefined) {
      completed = fields.completed === true;
      completedAt = completed ? new Date() : null;
    }
    if (fields.completionNote !== undefined) {
      completionNote =
        fields.completionNote != null && String(fields.completionNote).trim()
          ? String(fields.completionNote).slice(0, 8000)
          : null;
    }
    const r = await pgPool.query(
      `UPDATE meeting_ai_checklist_items SET
        title = $3, detail = $4, assignee = $5, due_note = $6,
        completed = $7, completed_at = $8, completion_note = $9, updated_at = NOW()
       WHERE id = $1::uuid AND user_email = $2
       RETURNING *`,
      [id, email, title, detail, assignee, dueNote, completed, completedAt, completionNote]
    );
    return rowToApi(r.rows?.[0]);
  }
  return withFileLock(async () => {
    const data = await readFileStore();
    const idx = data.items.findIndex((x) => x.id === id && x.user_email === email);
    if (idx < 0) return null;
    const row = data.items[idx];
    if (fields.title != null) row.title = String(fields.title).trim().slice(0, 2000);
    if (fields.detail !== undefined) {
      row.detail =
        fields.detail != null && String(fields.detail).trim() ? String(fields.detail).slice(0, 8000) : null;
    }
    if (fields.assignee !== undefined) row.assignee = fields.assignee ? String(fields.assignee).slice(0, 300) : null;
    if (fields.dueNote !== undefined) row.due_note = fields.dueNote ? String(fields.dueNote).slice(0, 300) : null;
    if (fields.completed !== undefined) {
      row.completed = fields.completed === true;
      row.completed_at = row.completed ? nowIso() : null;
    }
    if (fields.completionNote !== undefined) {
      row.completion_note =
        fields.completionNote != null && String(fields.completionNote).trim()
          ? String(fields.completionNote).slice(0, 8000)
          : null;
    }
    row.updated_at = nowIso();
    await writeFileStore(data);
    return rowToApi(row);
  });
}

/**
 * @param {import("pg").Pool | null} pgPool
 */
async function deleteItem(pgPool, id, email) {
  if (pgPool) {
    const r = await pgPool.query(`DELETE FROM meeting_ai_checklist_items WHERE id = $1::uuid AND user_email = $2 RETURNING id`, [
      id,
      email,
    ]);
    return { deleted: !!r.rowCount };
  }
  return withFileLock(async () => {
    const data = await readFileStore();
    const idx = data.items.findIndex((x) => x.id === id && x.user_email === email);
    if (idx < 0) return { deleted: false };
    data.items.splice(idx, 1);
    await writeFileStore(data);
    return { deleted: true };
  });
}

/**
 * 회의록 삭제 시 연동: 해당 회의에서 가져온 업무 체크리스트 항목 일괄 삭제
 * @param {import("pg").Pool | null} pgPool
 * @param {string} meetingId
 * @param {string} email
 * @returns {Promise<{ removed: number }>}
 */
async function deleteItemsByMeetingId(pgPool, meetingId, email) {
  if (!meetingId) return { removed: 0 };
  if (pgPool) {
    const r = await pgPool.query(
      `DELETE FROM meeting_ai_checklist_items WHERE meeting_id = $1::uuid AND user_email = $2`,
      [meetingId, email]
    );
    return { removed: r.rowCount || 0 };
  }
  return withFileLock(async () => {
    const data = await readFileStore();
    const mid = String(meetingId);
    const before = data.items.length;
    data.items = data.items.filter((x) => !(String(x.meeting_id || "") === mid && x.user_email === email));
    const removed = before - data.items.length;
    if (removed > 0) await writeFileStore(data);
    return { removed };
  });
}

/**
 * 회의록 본문에서 항목 파싱 후 삽입 (중복 title+meeting_id 스킵)
 * @param {import("pg").Pool | null} pgPool
 * @param {string} email
 * @param {string} meetingId
 * @param {Array<{ title: string, detail?: string, assignee?: string|null, due_note?: string|null, completed?: boolean }>} parsed
 */
async function insertImportedBatch(pgPool, email, meetingId, parsed) {
  const inserted = [];
  const existing = await listItems(pgPool, email, { meetingId });
  const keys = new Set(existing.map((e) => `${(e.title || "").trim()}::${e.meetingId || ""}`));

  let order = existing.length;
  for (const p of parsed) {
    const title = (p.title || "").trim();
    if (!title) continue;
    const key = `${title}::${meetingId}`;
    if (keys.has(key)) continue;
    keys.add(key);
    const item = await insertItem(pgPool, email, {
      title,
      detail: p.detail || "",
      assignee: p.assignee || null,
      dueNote: p.due_note || null,
      meetingId,
      source: "imported",
      completed: !!p.completed,
      sortOrder: order++,
    });
    inserted.push(item);
  }
  return inserted;
}

module.exports = {
  CHECKLIST_FILE,
  listItems,
  insertItem,
  updateItem,
  deleteItem,
  deleteItemsByMeetingId,
  insertImportedBatch,
};
