import type { Task } from '../types';
import { isSameWeek, parseIsoDate, toIsoDate } from './boardCalendar';

export interface TaskIssueEntry {
  id: string;
  text: string;
  showOnCard: boolean;
  /** YYYY-MM-DD — 주차 렌즈에서 해당 주에만 카드 표시 */
  occurredOn?: string | null;
}

export interface IssueVisibilityOptions {
  weekMonday?: Date;
}

export function newIssueEntry(text = '', occurredOn?: string): TaskIssueEntry {
  return {
    id: `issue-${Date.now()}-${Math.random().toString(36).slice(2, 9)}`,
    text,
    showOnCard: true,
    occurredOn: occurredOn ?? toIsoDate(new Date()),
  };
}

function normalizeOccurredOn(raw: unknown): string | null {
  if (typeof raw !== 'string' || !raw.trim()) return null;
  return parseIsoDate(raw.trim()) ? raw.trim() : null;
}

export function normalizeIssueEntries(raw: unknown): TaskIssueEntry[] {
  if (!Array.isArray(raw)) return [];
  const entries: TaskIssueEntry[] = [];
  for (const item of raw) {
    if (!item || typeof item !== 'object') continue;
    const row = item as Record<string, unknown>;
    const text = typeof row.text === 'string' ? row.text : '';
    entries.push({
      id: typeof row.id === 'string' && row.id ? row.id : newIssueEntry().id,
      text,
      showOnCard: row.showOnCard !== false,
      occurredOn: normalizeOccurredOn(row.occurredOn),
    });
  }
  return entries;
}

export function parseIssueEntries(task: Pick<Task, 'issueEntries' | 'issueNote' | 'showIssue'>): TaskIssueEntry[] {
  const fromJson = normalizeIssueEntries(task.issueEntries);
  if (fromJson.length > 0) return fromJson;
  const legacy = task.issueNote?.trim();
  if (!legacy) return [];
  return [{ id: 'legacy', text: legacy, showOnCard: task.showIssue !== false, occurredOn: null }];
}

function issueInWeek(entry: TaskIssueEntry, weekMonday: Date): boolean {
  if (!entry.occurredOn) return false;
  const day = parseIsoDate(entry.occurredOn);
  if (!day) return false;
  return isSameWeek(day, weekMonday);
}

export function getVisibleIssueEntries(
  task: Pick<Task, 'issueEntries' | 'issueNote' | 'showIssue'>,
  options?: IssueVisibilityOptions,
): TaskIssueEntry[] {
  const entries = parseIssueEntries(task).filter((entry) => entry.showOnCard && entry.text.trim());
  if (!options?.weekMonday) return entries;
  return entries.filter((entry) => issueInWeek(entry, options.weekMonday!));
}

export function hasVisibleIssue(
  task: Pick<Task, 'issueEntries' | 'issueNote' | 'showIssue'>,
  options?: IssueVisibilityOptions,
): boolean {
  return getVisibleIssueEntries(task, options).length > 0;
}

export function getPrimaryIssueText(
  task: Pick<Task, 'issueEntries' | 'issueNote' | 'showIssue'>,
  options?: IssueVisibilityOptions,
): string | null {
  const visible = getVisibleIssueEntries(task, options);
  if (visible.length > 0) return visible[visible.length - 1].text;
  return null;
}

export function serializeIssueEntries(entries: TaskIssueEntry[]): TaskIssueEntry[] {
  return entries
    .map((entry) => ({
      id: entry.id,
      text: entry.text.trim(),
      showOnCard: entry.showOnCard,
      occurredOn: entry.occurredOn?.trim() || null,
    }))
    .filter((entry) => entry.text.length > 0);
}
