import { cli, Strategy } from '@jackwener/opencli/registry';
import { ArgumentError } from '@jackwener/opencli/errors';
import { mubuPost, nodesToMarkdown, nodesToText, htmlToText } from './utils.js';

// ── 日期工具 ──────────────────────────────────────────────

function localToday() {
  const d = new Date();
  return { year: d.getFullYear(), month: d.getMonth() + 1, day: d.getDate() };
}

function lastDayOfMonth(year, month) {
  return new Date(year, month, 0).getDate();
}

function validateYear(year, label = '年份') {
  if (!Number.isInteger(year) || year < 1) {
    throw new ArgumentError(`${label} 非法：${year}，应为正整数`);
  }
}

function validateMonth(month) {
  if (!Number.isInteger(month) || month < 1 || month > 12) {
    throw new ArgumentError(`月份非法：${month}，应为 1-12`);
  }
}

function validateDay(year, month, day) {
  const maxDay = lastDayOfMonth(year, month);
  if (!Number.isInteger(day) || day < 1 || day > maxDay) {
    throw new ArgumentError(`日期非法：${year}-${month}-${day}（${year} 年 ${month} 月共 ${maxDay} 天）`);
  }
}

function parseDate(s) {
  const parts = s.split('-').map(Number);
  if (parts.length !== 3 || parts.some(isNaN)) {
    throw new ArgumentError(`日期格式错误：${s}，应为 YYYY-MM-DD`);
  }
  const [year, month, day] = parts;
  validateYear(year);
  validateMonth(month);
  validateDay(year, month, day);
  return { year, month, day };
}

function parseMonth(s) {
  const parts = s.split('-').map(Number);
  if (parts.length !== 2 || parts.some(isNaN)) {
    throw new ArgumentError(`月份格式错误：${s}，应为 YYYY-MM`);
  }
  const [year, month] = parts;
  validateYear(year);
  validateMonth(month);
  return { year, month };
}

function dateToKey(d) {
  return `${d.year}-${String(d.month).padStart(2, '0')}-${String(d.day).padStart(2, '0')}`;
}

/** 将各种时间参数统一解析为 {start, end} */
function resolveRange(kwargs) {
  const dateStr = kwargs.date;
  const monthStr = kwargs.month;
  const yearArg = kwargs.year;
  const fromStr = kwargs.from;
  const toStr = kwargs.to;

  // --from / --to 优先级最高
  if (fromStr || toStr) {
    if (!fromStr) throw new ArgumentError('使用 --to 时必须同时指定 --from');
    const start = parseDate(fromStr);
    const end = toStr ? parseDate(toStr) : localToday();
    if (dateToKey(start) > dateToKey(end)) throw new ArgumentError('--from 不能晚于 --to');
    return { start, end };
  }

  if (yearArg !== undefined && yearArg !== null) {
    validateYear(yearArg, '--year');
    return {
      start: { year: yearArg, month: 1, day: 1 },
      end: { year: yearArg, month: 12, day: 31 },
    };
  }

  if (monthStr) {
    const { year, month } = parseMonth(monthStr);
    return {
      start: { year, month, day: 1 },
      end: { year, month, day: lastDayOfMonth(year, month) },
    };
  }

  if (dateStr) {
    const d = parseDate(dateStr);
    return { start: d, end: d };
  }

  // 默认：今天
  const today = localToday();
  return { start: today, end: today };
}

// ── API 工具 ──────────────────────────────────────────────

async function getYearDocId(page, year) {
  const raw = await page.evaluate(`localStorage.getItem('daily_notes_doc_list')`);
  if (!raw) return null;
  const list = JSON.parse(raw);
  return list.find((d) => d.name === `${year}年`)?.id ?? null;
}

async function getYearNodes(page, docId) {
  const data = await mubuPost(page, '/document/edit/get', { docId });
  const def = JSON.parse(data.definition);
  return def.nodes ?? [];
}

/** 加载某年的所有 day 节点，返回带 dateKey 的列表 */
async function loadYearEntries(page, year) {
  const docId = await getYearDocId(page, year);
  if (!docId) return [];

  const yearNodes = await getYearNodes(page, docId);
  const entries = [];

  for (const monthNode of yearNodes) {
    const monthNum = parseInt(htmlToText(monthNode.text), 10);
    if (!monthNode.children?.length) continue;

    for (const dayNode of monthNode.children) {
      const plain = htmlToText(dayNode.text).replace(/\s+/g, ' ').trim();
      const compact = plain.replace(/\s/g, '');
      const match = compact.match(/^(\d+)月(\d+)日/);
      if (!match) continue;
      const m = parseInt(match[1], 10);
      const d = parseInt(match[2], 10);
      if (m !== monthNum) continue;

      const dateKey = dateToKey({ year, month: m, day: d });
      entries.push({ dateKey, label: plain, node: dayNode });
    }
  }

  return entries;
}

/** 收集 [start, end] 范围内涉及的所有年份 */
function yearsInRange(start, end) {
  const years = [];
  for (let y = start.year; y <= end.year; y++) years.push(y);
  return years;
}

// ── 命令 ──────────────────────────────────────────────────

cli({
  site: 'mubu',
  name: 'notes',
    access: 'read',
  description: '读取幕布速记（默认今天）。支持 --date/--month/--year/--from/--to 指定时间范围，--list 为概览模式（日期+条数）。',
  domain: 'mubu.com',
  strategy: Strategy.COOKIE,
  args: [
    {
      name: 'list',
      type: 'bool',
      default: false,
      help: '概览模式：只输出日期和条数，不含速记内容。可与任意时间范围参数组合。',
    },
    {
      name: 'date',
      help: '单日，格式 YYYY-MM-DD。不指定时间范围则默认今天（系统本地时间）。',
    },
    {
      name: 'month',
      help: '整月，格式 YYYY-MM。',
    },
    {
      name: 'year',
      type: 'int',
      help: '整年，格式 YYYY（整数）。',
    },
    {
      name: 'from',
      help: '范围起始日，格式 YYYY-MM-DD。须与 --to 同时使用。',
    },
    {
      name: 'to',
      help: '范围截止日，格式 YYYY-MM-DD。须与 --from 同时使用。',
    },
    {
      name: 'output',
      default: 'md',
      help: '输出格式：md（默认，Markdown）或 text（纯文本）',
    },
  ],
  columns: ['date', 'content'],
  func: async (page, kwargs) => {
    const isList = kwargs.list;
    const format = kwargs.output;
    if (format !== 'md' && format !== 'text') {
      throw new ArgumentError(`--output 只接受 md 或 text，收到：${format}`);
    }

    await page.goto('https://mubu.com/app');

    const { start, end } = resolveRange(kwargs);
    const startKey = dateToKey(start);
    const endKey = dateToKey(end);

    // 并行加载所有涉及年份的 day 节点，按范围过滤
    const yearResults = await Promise.all(
      yearsInRange(start, end).map((year) => loadYearEntries(page, year)),
    );
    const allEntries = yearResults
      .flat()
      .filter((e) => e.dateKey >= startKey && e.dateKey <= endKey);

    if (allEntries.length === 0) {
      const label = startKey === endKey ? startKey : `${startKey} ~ ${endKey}`;
      return [{ date: label, content: '该时间段暂无速记' }];
    }

    // 概览模式
    if (isList) {
      return allEntries.map((e) => ({
        date: e.label,
        content: `${e.node.children?.length ?? 0} 条记录`,
      }));
    }

    // 内容模式
    const render = (children) =>
      format === 'text' ? nodesToText(children) : nodesToMarkdown(children);

    return allEntries
      .filter((e) => e.node.children?.length)
      .map((e) => ({
        date: e.label,
        content: render(e.node.children ?? []) || '（空）',
      }));
  },
});
