/**
 * 경영성과 대시보드: 엑셀 업로드 파싱·스냅샷 저장·최신 페이로드 조회
 */
const fs = require("fs");
const path = require("path");

function loadXlsx() {
  try {
    return require("xlsx");
  } catch {
    return null;
  }
}

const ROOT = path.join(__dirname, "..");
const DEFAULT_PAYLOAD_PATH = path.join(ROOT, "config", "mgmt-perf-default-payload.json");
const FILE_STATE_PATH = path.join(ROOT, "data", "mgmt-perf-last-state.json");

function loadDefaultPayload() {
  const raw = fs.readFileSync(DEFAULT_PAYLOAD_PATH, "utf8");
  return JSON.parse(raw);
}

/**
 * 매출일보 시트를 읽어 기본 페이로드에 메타를 덧붙입니다. (집계 치환은 추후 확장)
 * @param {Buffer} buffer
 * @param {object} defaultPayload
 */
function buildPayloadFromWorkbook(buffer, defaultPayload) {
  const XLSX = loadXlsx();
  if (!XLSX) {
    const payload = JSON.parse(JSON.stringify(defaultPayload));
    payload._uploadMeta = {
      sheets: [],
      primarySheet: null,
      rowCount: 0,
      importedAt: new Date().toISOString(),
      note: "npm 패키지 `xlsx`가 없어 엑셀을 파싱하지 못했습니다. 프로젝트 루트에서 `npm install` 후 서버를 재시작하세요.",
    };
    return payload;
  }
  const wb = XLSX.read(buffer, { type: "buffer", cellDates: true });
  const names = wb.SheetNames || [];
  const sheetName = names.includes("매출일보") ? "매출일보" : names[0];
  const ws = wb.Sheets[sheetName];
  const matrix = XLSX.utils.sheet_to_json(ws, { header: 1, defval: "" });
  const nonEmptyRows = matrix.filter((r) => Array.isArray(r) && r.some((c) => c !== "" && c != null));
  const payload = JSON.parse(JSON.stringify(defaultPayload));
  payload._uploadMeta = {
    sheets: names,
    primarySheet: sheetName,
    rowCount: nonEmptyRows.length,
    importedAt: new Date().toISOString(),
    note:
      "매출일보 행 수·시트명만 반영했습니다. 차트 수치를 엑셀 집계로 치환하려면 별도 매핑 로직이 필요합니다.",
  };
  return payload;
}

/**
 * @param {import("pg").Pool | null} pgPool
 * @param {{ userEmail: string | null, originalFilename: string, filePath: string, fiscalYear: number, quarter: number, payload: object }} row
 */
async function saveUploadAndSnapshot(pgPool, row) {
  const { userEmail, originalFilename, filePath, fiscalYear, quarter, payload } = row;
  const stat = fs.statSync(filePath);
  if (!pgPool) {
    fs.writeFileSync(
      FILE_STATE_PATH,
      JSON.stringify(
        {
          payload,
          meta: {
            originalFilename,
            fiscalYear,
            quarter,
            savedAt: new Date().toISOString(),
            fileSize: stat.size,
          },
        },
        null,
        2
      ),
      "utf8"
    );
    return { id: null, fileBacked: true };
  }
  const ins = await pgPool.query(
    `INSERT INTO mgmt_perf_uploads (user_email, original_filename, fiscal_year, quarter, file_path, file_size, parse_status)
     VALUES ($1,$2,$3,$4,$5,$6,'ok')
     RETURNING id`,
    [userEmail || null, originalFilename, fiscalYear, quarter, filePath, stat.size]
  );
  const uploadId = ins.rows[0].id;
  await pgPool.query(`INSERT INTO mgmt_perf_snapshots (upload_id, payload) VALUES ($1, $2::jsonb)`, [
    uploadId,
    JSON.stringify(payload),
  ]);
  return { id: uploadId, fileBacked: false };
}

/**
 * @param {import("pg").Pool | null} pgPool
 */
async function getLatestPayloadRow(pgPool) {
  if (pgPool) {
    const r = await pgPool.query(`
      SELECT s.payload, u.fiscal_year, u.quarter, u.original_filename, u.created_at
      FROM mgmt_perf_snapshots s
      JOIN mgmt_perf_uploads u ON u.id = s.upload_id
      ORDER BY u.created_at DESC
      LIMIT 1
    `);
    if (r.rows[0]) {
      const row = r.rows[0];
      return {
        payload: row.payload,
        fiscal_year: row.fiscal_year,
        quarter: row.quarter,
        original_filename: row.original_filename,
        created_at: row.created_at,
      };
    }
  }
  try {
    const j = JSON.parse(fs.readFileSync(FILE_STATE_PATH, "utf8"));
    return {
      payload: j.payload,
      fiscal_year: j.meta?.fiscalYear,
      quarter: j.meta?.quarter,
      original_filename: j.meta?.originalFilename,
      created_at: j.meta?.savedAt ? new Date(j.meta.savedAt) : null,
    };
  } catch {
    return {
      payload: loadDefaultPayload(),
      fiscal_year: new Date().getFullYear(),
      quarter: 1,
      original_filename: null,
      created_at: null,
    };
  }
}

/**
 * DB에 저장된 연도·분기별 최신 스냅샷 1건. 해당 기간 업로드가 없으면 기본 페이로드와 `_noSnapshotForPeriod`.
 * @param {import("pg").Pool | null} pgPool
 * @param {number} fiscalYear
 * @param {number} quarter 1–4
 */
async function getPayloadRowForPeriod(pgPool, fiscalYear, quarter) {
  const y = Math.min(2100, Math.max(2020, Math.floor(Number(fiscalYear)) || new Date().getFullYear()));
  const q = Math.min(4, Math.max(1, Math.floor(Number(quarter)) || 1));

  if (pgPool) {
    const r = await pgPool.query(
      `
      SELECT s.payload, u.fiscal_year, u.quarter, u.original_filename, u.created_at
      FROM mgmt_perf_snapshots s
      JOIN mgmt_perf_uploads u ON u.id = s.upload_id
      WHERE u.fiscal_year = $1 AND u.quarter = $2
      ORDER BY u.created_at DESC
      LIMIT 1
    `,
      [y, q]
    );
    if (r.rows[0]) {
      const row = r.rows[0];
      return {
        payload: row.payload,
        fiscal_year: row.fiscal_year,
        quarter: row.quarter,
        original_filename: row.original_filename,
        created_at: row.created_at,
        _noSnapshotForPeriod: false,
      };
    }
    return {
      payload: loadDefaultPayload(),
      fiscal_year: y,
      quarter: q,
      original_filename: null,
      created_at: null,
      _noSnapshotForPeriod: true,
    };
  }

  try {
    const j = JSON.parse(fs.readFileSync(FILE_STATE_PATH, "utf8"));
    const my = j.meta?.fiscalYear;
    const mq = j.meta?.quarter;
    if (my === y && mq === q) {
      return {
        payload: j.payload,
        fiscal_year: y,
        quarter: q,
        original_filename: j.meta?.originalFilename,
        created_at: j.meta?.savedAt ? new Date(j.meta.savedAt) : null,
        _noSnapshotForPeriod: false,
      };
    }
  } catch (_) {
    /* no file */
  }
  return {
    payload: loadDefaultPayload(),
    fiscal_year: y,
    quarter: q,
    original_filename: null,
    created_at: null,
    _noSnapshotForPeriod: true,
  };
}

/**
 * 업로드가 존재하는 (연도, 분기) 목록 — 조회 셀렉트 옵션용
 * @param {import("pg").Pool | null} pgPool
 */
async function listDistinctPeriods(pgPool) {
  if (!pgPool) {
    try {
      const j = JSON.parse(fs.readFileSync(FILE_STATE_PATH, "utf8"));
      if (j.meta?.fiscalYear != null && j.meta?.quarter != null) {
        return [{ fiscal_year: j.meta.fiscalYear, quarter: j.meta.quarter }];
      }
    } catch (_) {
      /* empty */
    }
    return [];
  }
  const r = await pgPool.query(`
    SELECT DISTINCT fiscal_year, quarter
    FROM mgmt_perf_uploads
    ORDER BY fiscal_year DESC, quarter DESC
  `);
  return r.rows;
}

/**
 * @param {import("pg").Pool | null} pgPool
 * @param {number} [limit=20]
 */
async function listUploads(pgPool, limit = 20) {
  if (!pgPool) {
    try {
      const j = JSON.parse(fs.readFileSync(FILE_STATE_PATH, "utf8"));
      return [
        {
          id: "file",
          original_filename: j.meta?.originalFilename,
          fiscal_year: j.meta?.fiscalYear,
          quarter: j.meta?.quarter,
          created_at: j.meta?.savedAt,
          parse_status: "ok",
        },
      ];
    } catch {
      return [];
    }
  }
  const r = await pgPool.query(
    `SELECT id, original_filename, fiscal_year, quarter, parse_status, created_at
     FROM mgmt_perf_uploads
     ORDER BY created_at DESC
     LIMIT $1`,
    [limit]
  );
  return r.rows;
}

/**
 * 업로드 행 삭제(PG: 스냅샷은 ON DELETE CASCADE). 디스크의 업로드 파일도 제거합니다.
 * 파일 전용 모드: `id === "file"` 일 때 스냅샷 JSON만 삭제합니다.
 * @param {import("pg").Pool | null} pgPool
 * @param {string} uploadId UUID 또는 `"file"`
 */
async function deleteUpload(pgPool, uploadId) {
  const id = String(uploadId || "").trim();
  if (!id) return { ok: false, error: "id가 없습니다." };

  if (!pgPool) {
    if (id !== "file") return { ok: false, error: "지원하지 않는 항목입니다." };
    try {
      if (fs.existsSync(FILE_STATE_PATH)) fs.unlinkSync(FILE_STATE_PATH);
    } catch (e) {
      return { ok: false, error: e.message || "삭제 실패" };
    }
    return { ok: true, fileBacked: true };
  }

  const uuidRe = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
  if (!uuidRe.test(id)) return { ok: false, error: "잘못된 id입니다." };

  const r = await pgPool.query(`DELETE FROM mgmt_perf_uploads WHERE id = $1::uuid RETURNING file_path`, [id]);
  if (r.rowCount === 0) return { ok: false, error: "항목을 찾을 수 없습니다." };
  const fp = r.rows[0].file_path;
  if (fp && fs.existsSync(fp)) {
    try {
      fs.unlinkSync(fp);
    } catch (_) {
      /* 로그만; DB는 이미 삭제됨 */
    }
  }
  return { ok: true };
}

module.exports = {
  loadDefaultPayload,
  buildPayloadFromWorkbook,
  saveUploadAndSnapshot,
  getLatestPayloadRow,
  getPayloadRowForPeriod,
  listDistinctPeriods,
  listUploads,
  deleteUpload,
  FILE_STATE_PATH,
};
