import { access, mkdir, readFile, writeFile } from 'node:fs/promises';
import path from 'node:path';

const KST_TIME_ZONE = 'Asia/Seoul';
export const DEFAULT_DAILY_CREATE_TIME = '18:00';
const DEFAULT_WORKLOG_TEMPLATE = `# YYYY-MM-DD 작업일지

## 오늘 작업

- 

## 이슈 및 해결

- 

## 결정 사항

- 

## 상세 작업 내역

- 
- 이 섹션에는 파일 목록, 경로 나열, raw diff를 직접 풀어쓰지 말고 작업 흐름과 판단만 정리
- 파일 목록은 변경/신규 파일 섹션에, raw diff는 소스 섹션에만 기록

## 스크린샷

- 전체 화면 스크린샷 1장은 필수
- 위젯/컴포넌트 단위 부분 스크린샷은 필요한 만큼 추가
- 저장소 기준 연결된 스크린샷이 없으면 작업 종료 전 반드시 채움

## 소스

### 파일 1: \`path/to/file.tsx\`

- 변경 또는 신규 추가 목적과 핵심 내용을 한 줄로 정리
- \`상세 작업 내역\`에는 파일 목록이나 raw diff를 다시 쓰지 않음
- \`소스\` 탭에서 Codex preview 스타일의 \`전체소스 / raw diff\` 전환을 제공하므로 여기에는 파일별 raw diff 위주로 남김

\`\`\`diff
# 이 파일의 raw diff
- before
+ after
\`\`\`

### 파일 2: \`path/to/another-file.ts\`

- 필요 없으면 이 섹션은 삭제

## 실행 커맨드

\`\`\`bash
\`\`\`

## 변경/신규 파일

- 
`;

const OBSOLETE_WORKLOG_SECTION_TITLES = new Set([
  '커밋 목록',
  '변경 요약',
  '변경 통계',
  '라인 통계',
]);

type KstNowParts = {
  dateKey: string;
  minutesOfDay: number;
};

function extractKstParts(date: Date) {
  const parts = new Intl.DateTimeFormat('en-CA', {
    timeZone: KST_TIME_ZONE,
    year: 'numeric',
    month: '2-digit',
    day: '2-digit',
    hour: '2-digit',
    minute: '2-digit',
    hour12: false,
  }).formatToParts(date);

  const values = Object.fromEntries(parts.filter((part) => part.type !== 'literal').map((part) => [part.type, part.value]));
  return {
    year: Number(values.year ?? '0'),
    month: Number(values.month ?? '0'),
    day: Number(values.day ?? '0'),
    hour: Number(values.hour ?? '0'),
    minute: Number(values.minute ?? '0'),
  };
}

export function isValidDailyCreateTime(value: string | undefined): value is string {
  return typeof value === 'string' && /^\d{2}:\d{2}$/.test(value);
}

export function normalizeDailyCreateTime(value: string | undefined) {
  return isValidDailyCreateTime(value) ? value : DEFAULT_DAILY_CREATE_TIME;
}

export function getKstNowParts(date = new Date()): KstNowParts {
  const { year, month, day, hour, minute } = extractKstParts(date);
  return {
    dateKey: `${String(year).padStart(4, '0')}-${String(month).padStart(2, '0')}-${String(day).padStart(2, '0')}`,
    minutesOfDay: hour * 60 + minute,
  };
}

export function isWorklogCreationDue(now: Date, dailyCreateTime: string, alreadyExecutedToday: boolean) {
  if (alreadyExecutedToday) {
    return false;
  }

  const [hours, minutes] = normalizeDailyCreateTime(dailyCreateTime).split(':').map((value) => Number(value));
  const nowParts = getKstNowParts(now);
  return nowParts.minutesOfDay >= (hours * 60 + minutes);
}

export function renderWorklogTemplate(template: string, dateKey: string) {
  return template.replaceAll('YYYY-MM-DD', dateKey);
}

function normalizeLevelTwoHeading(line: string) {
  const match = line.match(/^##\s+([^\n]+)$/m);

  if (!match) {
    return '';
  }

  return match[1]?.replace(/\s+\(.*\)\s*$/u, '').trim() ?? '';
}

function stripObsoleteWorklogSections(content: string) {
  const sections = content.split(/\n(?=##\s+)/);
  const preservedSections = sections.filter((section) => {
    const normalizedHeading = normalizeLevelTwoHeading(section);
    return !OBSOLETE_WORKLOG_SECTION_TITLES.has(normalizedHeading);
  });

  return `${preservedSections.join('\n\n').replace(/\n{3,}/g, '\n\n').trimEnd()}\n`;
}

const LEGACY_SOURCE_SECTION = `## 소스

- 요약 설명
- \`path/to/file.tsx\`: 변경 또는 신규 추가 목적과 핵심 내용을 한 줄로 정리

\`\`\`diff
# 핵심 diff를 1~3개 블록으로 기록
- before
+ after
\`\`\``;

const FILE_SCOPED_SOURCE_SECTION = `## 소스

### 파일 1: \`path/to/file.tsx\`

- 변경 또는 신규 추가 목적과 핵심 내용을 한 줄로 정리
- \`상세 작업 내역\`에는 파일 목록이나 raw diff를 다시 쓰지 않음
- \`소스\` 탭에서 Codex preview 스타일의 \`전체소스 / raw diff\` 전환을 제공하므로 여기에는 파일별 raw diff 위주로 남김

\`\`\`diff
# 이 파일의 raw diff
- before
+ after
\`\`\`

### 파일 2: \`path/to/another-file.ts\`

- 필요 없으면 이 섹션은 삭제`;

export function upgradeLegacyWorklogContent(content: string) {
  let upgradedContent = content;

  if (upgradedContent.includes(LEGACY_SOURCE_SECTION)) {
    upgradedContent = upgradedContent.replace(LEGACY_SOURCE_SECTION, FILE_SCOPED_SOURCE_SECTION);
  }

  upgradedContent = upgradedContent
    .replace(
      '## 상세 작업 내역\n\n- ',
      `## 상세 작업 내역

- 
- 이 섹션에는 파일 목록, 경로 나열, raw diff를 직접 풀어쓰지 말고 작업 흐름과 판단만 정리
- 파일 목록은 \`## 변경/신규 파일\`, raw diff는 \`## 소스\`에서만 기록`,
    )
    .replace(
      '## 스크린샷\n\n- 저장소 기준 연결된 스크린샷 없음',
      `## 스크린샷

- 전체 화면 스크린샷 1장은 필수
- 위젯/컴포넌트 단위 부분 스크린샷은 필요한 만큼 추가
- 저장소 기준 연결된 스크린샷이 없으면 작업 종료 전 반드시 채움`,
    )
    .replaceAll('# 이 파일의 핵심 diff', '# 이 파일의 raw diff')
    .replaceAll('`작업일지` 탭에는 중복 파일 목록을 다시 쓰지 않아도 됨', '`상세 작업 내역`에는 파일 목록이나 raw diff를 다시 쓰지 않음')
    .replaceAll('`소스` 탭에서 전체소스/diff를 전환해 보므로 여기에는 파일별 raw diff 위주로 남김', '`소스` 탭에서 Codex preview 스타일의 `전체소스 / raw diff` 전환을 제공하므로 여기에는 파일별 raw diff 위주로 남김');

  return stripObsoleteWorklogSections(upgradedContent);
}

async function readWorklogTemplate(repoPath: string) {
  const templatePath = path.join(repoPath, 'docs', 'templates', 'worklog-template.md');

  try {
    return await readFile(templatePath, 'utf8');
  } catch {
    return DEFAULT_WORKLOG_TEMPLATE;
  }
}

export async function ensureDailyWorklogFile(repoPath: string, dateKey: string) {
  const worklogPath = path.join(repoPath, 'docs', 'worklogs', `${dateKey}.md`);

  try {
    await access(worklogPath);
    const existingContent = await readFile(worklogPath, 'utf8');
    const upgradedContent = upgradeLegacyWorklogContent(existingContent);

    if (upgradedContent !== existingContent) {
      await writeFile(worklogPath, upgradedContent, 'utf8');
    }

    return worklogPath;
  } catch {
    const template = await readWorklogTemplate(repoPath);
    await mkdir(path.dirname(worklogPath), { recursive: true });
    await writeFile(worklogPath, renderWorklogTemplate(template, dateKey), 'utf8');
    return worklogPath;
  }
}
