import { writeFileSync } from "node:fs";
import { resolve } from "node:path";
import type { FieldDescription, JsonValue } from "@arco/clarizen-lib";
import type { EntityChoice } from "../metadata/picker.js";
import { formatFilterSummary, type EntityFilter } from "../query/filter.js";
import type { EntityRecord } from "../query/fetch-all.js";
import type { BulkUpdateResult } from "../update/bulk-field.js";

export interface RunLogEntry {
  id: string;
  displayName?: string;
  status: "updated" | "error";
  message?: string;
  errorCode?: string;
}

export interface RunLog {
  executedAt: string;
  durationMs: number;
  userId: string;
  operation: {
    typeName: string;
    typeLabel?: string;
    filter: string;
    fieldName: string;
    fieldLabel?: string;
    fieldType?: string;
    value: JsonValue;
    valueLabel?: string;
  };
  summary: {
    total: number;
    updated: number;
    errors: number;
  };
  results: RunLogEntry[];
}

export interface BuildRunLogParams {
  startedAt: number;
  userId: string;
  entityChoice: EntityChoice;
  entityFilter: EntityFilter;
  field: FieldDescription;
  fieldName: string;
  parsedValue: JsonValue;
  valueDisplayLabel?: string;
  records: EntityRecord[];
  result: BulkUpdateResult;
}

function logTimestamp(): string {
  return new Date().toISOString().replace(/[:.]/g, "-");
}

export function buildRunLog(params: BuildRunLogParams): RunLog {
  const {
    startedAt,
    userId,
    entityChoice,
    entityFilter,
    field,
    fieldName,
    parsedValue,
    valueDisplayLabel,
    records,
    result,
  } = params;

  const errorsById = new Map(
    result.errors.map((e) => [String(e.id), e] as const),
  );

  const results: RunLogEntry[] = records.map((record) => {
    const id = String(record.id);
    const error = errorsById.get(id);

    if (error) {
      return {
        id,
        displayName: record.displayName,
        status: "error",
        message: error.message,
        errorCode: error.errorCode,
      };
    }

    return {
      id,
      displayName: record.displayName,
      status: "updated",
    };
  });

  return {
    executedAt: new Date().toISOString(),
    durationMs: Date.now() - startedAt,
    userId,
    operation: {
      typeName: entityChoice.typeName,
      typeLabel: entityChoice.label,
      filter: formatFilterSummary(entityFilter),
      fieldName,
      fieldLabel: field.label,
      fieldType: field.type,
      value: parsedValue,
      valueLabel: valueDisplayLabel,
    },
    summary: {
      total: records.length,
      updated: result.updated,
      errors: result.errors.length,
    },
    results,
  };
}

export function writeRunLog(log: RunLog, cwd = process.cwd()): string {
  const filePath = resolve(cwd, `run-log-${logTimestamp()}.json`);
  writeFileSync(filePath, JSON.stringify(log, null, 2), "utf-8");
  return filePath;
}
