import { AssemblyMonitoringUnitDetailDbDto } from 'src/api/monitoring/cp/assembly/dto/internal/unit-detail.db.dto';
import {
  AssemblyMonitoringUnitDetailResponseDto,
  AssemblyMonitoringUnitProcessStepResponseDto,
  AssemblyMonitoringUnitProcessStatus,
} from 'src/api/monitoring/cp/assembly/dto/response/unit-detail.response.dto';

const STATUS_MAP: Record<string, AssemblyMonitoringUnitProcessStatus> = {
  완료: 'COMPLETED',
  완성: 'COMPLETED',
  미완: 'NOT_STARTED',
};

const toNumber = (value: number | string | null | undefined): number => {
  if (typeof value === 'number' && Number.isFinite(value)) return value;
  const parsed = Number(value);
  return Number.isFinite(parsed) ? parsed : 0;
};

const toSortNumber = (value: number | string | null | undefined): number => {
  const parsed = Number(value);
  return Number.isFinite(parsed) ? parsed : Number.MAX_SAFE_INTEGER;
};

const toText = (value: string | number | null | undefined): string => {
  if (typeof value === 'string') return value.trim();
  if (typeof value === 'number') return String(value);
  return '';
};

const extractDurationText = (work: string): string | null => {
  const afterSlash = work.split('/')[1] ?? work;
  const beforeParen = afterSlash.split('(')[0] ?? '';
  const trimmed = beforeParen.replace(/\s+/g, ' ').trim();
  return trimmed ? trimmed : null;
};

const parseDurationMinutes = (durationText: string | null): number | null => {
  if (!durationText) return null;
  const hourMatch = durationText.match(/(\d+)\s*시간/);
  const minuteMatch = durationText.match(/(\d+)\s*분/);
  if (!hourMatch && !minuteMatch) return null;
  const hours = hourMatch ? Number(hourMatch[1]) : 0;
  const minutes = minuteMatch ? Number(minuteMatch[1]) : 0;
  return hours * 60 + minutes;
};

const parseCompletedAt = (work: string): string | null => {
  const match = work.match(/\(([^)]*)\)/);
  const token = match?.[1]?.match(/\d{8}/)?.[0];
  if (!token) return null;
  return `${token.slice(0, 4)}-${token.slice(4, 6)}-${token.slice(6, 8)}`;
};

const parseStatus = (work: string): AssemblyMonitoringUnitProcessStatus => {
  const statusLabel = work.split('/')[0]?.trim() ?? '';
  return STATUS_MAP[statusLabel] ?? 'IN_PROGRESS';
};

const buildSteps = (
  row: AssemblyMonitoringUnitDetailDbDto,
): AssemblyMonitoringUnitProcessStepResponseDto[] => {
  const pairs: Array<[string | null, string | null]> = [
    [row.Proc1, row.Work1],
    [row.Proc2, row.Work2],
    [row.Proc3, row.Work3],
    [row.Proc4, row.Work4],
    [row.Proc5, row.Work5],
  ];

  const steps: AssemblyMonitoringUnitProcessStepResponseDto[] = [];

  for (const [proc, work] of pairs) {
    const name = toText(proc);
    const rawWork = toText(work);
    if (!name || !rawWork) continue;

    const durationText = extractDurationText(rawWork);
    const durationMinutes = parseDurationMinutes(durationText);

    steps.push({
      name,
      status: parseStatus(rawWork),
      completedAt: parseCompletedAt(rawWork),
      durationMinutes,
      durationText,
      rawWork,
    });
  }

  return steps;
};

const compareRows = (
  left: AssemblyMonitoringUnitDetailDbDto,
  right: AssemblyMonitoringUnitDetailDbDto,
): number => {
  const planDiff = toNumber(left.ProdPlanSeq) - toNumber(right.ProdPlanSeq);
  if (planDiff !== 0) return planDiff;

  const serialLeft = toText(left.SerialNo);
  const serialRight = toText(right.SerialNo);
  if (serialLeft !== serialRight) return serialLeft.localeCompare(serialRight);

  return toSortNumber(left.RowBlock) - toSortNumber(right.RowBlock);
};

const buildKey = (row: AssemblyMonitoringUnitDetailDbDto): string =>
  `${toNumber(row.ProdPlanSeq)}|${toText(row.SerialNo)}`;

export const buildUnitDetailTracks = (
  rows: AssemblyMonitoringUnitDetailDbDto[],
): AssemblyMonitoringUnitDetailResponseDto[] => {
  if (!rows.length) return [];

  const sortedRows = [...rows].sort(compareRows);
  const groups = new Map<string, AssemblyMonitoringUnitDetailDbDto[]>();

  for (const row of sortedRows) {
    const key = buildKey(row);
    const list = groups.get(key);
    if (list) {
      list.push(row);
    } else {
      groups.set(key, [row]);
    }
  }

  const tracks: AssemblyMonitoringUnitDetailResponseDto[] = [];

  for (const groupRows of groups.values()) {
    const base = groupRows[0];
    const steps = groupRows.flatMap(buildSteps);

    tracks.push({
      prodPlanSeq: toNumber(base.ProdPlanSeq),
      prodPlanNo: toText(base.ProdPlanNo),
      modelSeq: toNumber(base.ModelSeq),
      serialNo: toText(base.SerialNo),
      modelName: toText(base.ModelName),
      steps,
    });
  }

  return tracks;
};
