import path from 'node:path';
import { mkdir, readFile, writeFile } from 'node:fs/promises';
import { getEnv } from '../config/env.js';
import {
  type AutomationContextRecord,
  getAutomationContextsConfig,
  normalizeAutomationContextSelection,
  resolveAutomationContexts,
} from './automation-context-config-service.js';
import type { AutomationTypeRecord } from './automation-type-config-service.js';

export function stringifyAutomationContextIds(value: unknown) {
  return JSON.stringify(normalizeAutomationContextSelection(value));
}

export function parseAutomationContextIds(value: unknown) {
  if (Array.isArray(value)) {
    return normalizeAutomationContextSelection(value);
  }

  if (typeof value !== 'string') {
    return [];
  }

  const trimmed = value.trim();

  if (!trimmed) {
    return [];
  }

  try {
    const parsed = JSON.parse(trimmed);
    return normalizeAutomationContextSelection(parsed);
  } catch {
    return normalizeAutomationContextSelection(trimmed);
  }
}

export function buildAutomationContextMarkdown(
  contexts: Awaited<ReturnType<typeof getAutomationContextsConfig>> | null | undefined,
  selectedContextIds?: unknown,
) {
  const resolvedContexts = resolveAutomationContexts(contexts, selectedContextIds);

  if (resolvedContexts.length === 0) {
    return '선택된 자동화 Context 없음';
  }

  return resolvedContexts
    .map((item) => [`### ${item.title}`, item.content.trim() || '(내용 없음)'].join('\n'))
    .join('\n\n');
}

export async function buildAutomationNoteSections(options: {
  title?: string;
  sourceLabel: string;
  requestContent: string;
  attachments?: string[];
  automationType?: Pick<AutomationTypeRecord, 'name'> | null;
  availableContexts?: AutomationContextRecord[];
  selectedContextIds?: unknown;
  extraSections?: string[];
}) {
  const availableContexts = options.availableContexts ?? (await getAutomationContextsConfig());
  const lines = [
    '# 자동화 작업메모',
    '',
    options.title?.trim() ? `- 게시판 제목: ${options.title.trim()}` : null,
    `- 메모 출처: ${options.sourceLabel}`,
    options.automationType?.name?.trim() ? `- 선택 자동화 유형: ${options.automationType.name.trim()}` : null,
    '- 자동화 처리 원칙: 아래에서 선택된 자동화 Context만 우선 참조합니다.',
    '',
    '## 자동화 Context',
    buildAutomationContextMarkdown(availableContexts, options.selectedContextIds),
    '',
    ...(options.extraSections ?? []),
    '## 요청 본문',
    options.requestContent.trim(),
    ...(options.attachments?.length ? ['', '## 첨부 파일', ...options.attachments] : []),
  ];

  return lines.filter((line): line is string => line !== null && line !== undefined).join('\n');
}

function extractRequestedPaths(note: string) {
  const matches = note.match(/(?:[A-Za-z0-9._-]+[\/\\])+[A-Za-z0-9._-]+(?:\.[A-Za-z0-9._-]+)?/g) ?? [];
  return [...new Set(matches.map((item) => item.replace(/\\/g, '/')))];
}

async function tryReadFile(filePath: string) {
  try {
    return await readFile(filePath, 'utf8');
  } catch {
    return null;
  }
}

function limitText(value: string, maxChars = 12000) {
  const normalized = value.trim();
  return normalized.length <= maxChars ? normalized : `${normalized.slice(0, maxChars).trimEnd()}\n\n...`;
}

function getScheduleRepoRoot() {
  const env = getEnv();
  return env.SERVER_COMMAND_MAIN_PROJECT_ROOT || env.PLAN_MAIN_PROJECT_REPO_PATH || process.cwd();
}

export async function ensureSchedulePromptSnapshot(options: {
  scheduleId: number;
  workId: string;
  note: string;
  forceRefresh?: boolean;
}) {
  const repoRoot = getScheduleRepoRoot();
  const scheduleDir = path.join(repoRoot, '.auto_codex', 'schedule', String(options.scheduleId));
  await mkdir(scheduleDir, { recursive: true });

  const requestPath = path.join(scheduleDir, 'request.md');
  const contextPath = path.join(scheduleDir, 'context.md');
  const manifestPath = path.join(scheduleDir, 'manifest.json');

  const requestedPaths = extractRequestedPaths(options.note);
  const candidatePaths = [
    'AGENTS.md',
    'docs/README.md',
    ...requestedPaths.filter((item) => !item.startsWith('http://') && !item.startsWith('https://')),
  ];
  const uniqueRelativePaths = [...new Set(candidatePaths)];

  const references: string[] = [];

  for (const relativePath of uniqueRelativePaths) {
    const absolutePath = path.resolve(repoRoot, relativePath);
    const content = await tryReadFile(absolutePath);

    if (!content) {
      continue;
    }

    references.push(`## ${relativePath}\n\n\`\`\`\n${limitText(content)}\n\`\`\``);
  }

  const requestMarkdown = [
    '# 스케줄 요청 원문',
    '',
    `- 스케줄 ID: ${options.scheduleId}`,
    `- 작업 ID: ${options.workId}`,
    '',
    '## 원본 메모',
    options.note.trim() || '(비어 있음)',
  ].join('\n');

  const contextMarkdown = [
    '# 스케줄 전용 참조',
    '',
    '- 최초 활성화 시점에 읽은 요청/문서/소스 일부를 이 디렉터리 아래로 정리했습니다.',
    '- 이후 자동화 실행은 우선 이 디렉터리의 Markdown 문서를 참조하고, 원본 소스 재탐색은 꼭 필요할 때만 제한적으로 수행합니다.',
    '',
    ...(references.length > 0 ? references : ['## 참조 문서', '별도로 추출된 문서가 없습니다. request.md를 우선 참조합니다.']),
  ].join('\n\n');

  await writeFile(requestPath, `${requestMarkdown}\n`, 'utf8');
  await writeFile(contextPath, `${contextMarkdown}\n`, 'utf8');
  await writeFile(
    manifestPath,
    JSON.stringify(
      {
        scheduleId: options.scheduleId,
        workId: options.workId,
        refreshedAt: new Date().toISOString(),
        forceRefresh: Boolean(options.forceRefresh),
        sourcePaths: uniqueRelativePaths,
      },
      null,
      2,
    ),
    'utf8',
  );

  const relativeDir = path.relative(repoRoot, scheduleDir).replace(/\\/g, '/');
  return {
    directory: relativeDir,
    requestPath: `${relativeDir}/request.md`,
    contextPath: `${relativeDir}/context.md`,
    manifestPath: `${relativeDir}/manifest.json`,
  };
}
