import {
  type AuditDetails,
  type CommonAuditLog,
  formatAuditValue,
  parseAuditDetails,
  resolveAuditActor,
} from "../../../../common/core/audit";
import type { ClientSummary, DevAuditLog } from "../../lib/devApi";
import { t } from "../../lib/i18n";

export type RecentClientChange = {
  eventId: string;
  clientId: string;
  clientName: string;
  actorId: string;
  action: string;
  actionLabel: string;
  timestamp: string;
  detailLabels: Array<{ label: string; value: string }>;
};

const recentClientActions = new Set([
  "CREATE_CLIENT",
  "UPDATE_CLIENT",
  "UPDATE_CLIENT_STATUS",
  "ROTATE_SECRET",
  "ADD_RELATION",
  "REMOVE_RELATION",
  "DELETE_CLIENT",
]);

function isRecord(value: unknown): value is Record<string, unknown> {
  return Boolean(value) && typeof value === "object" && !Array.isArray(value);
}

export function getRecentClientActionLabel(action: string) {
  switch (action) {
    case "CREATE_CLIENT":
      return t("ui.dev.clients.recent_changes.guide.create", "앱 생성");
    case "UPDATE_CLIENT":
      return t("ui.dev.clients.recent_changes.guide.settings", "설정 변경");
    case "UPDATE_CLIENT_STATUS":
      return t("ui.dev.clients.recent_changes.guide.status", "상태 변경");
    case "ROTATE_SECRET":
      return t(
        "ui.dev.clients.recent_changes.guide.secret",
        "클라이언트 시크릿 재발급",
      );
    case "ADD_RELATION":
      return t("ui.dev.clients.relationships.add_title", "관계 추가");
    case "REMOVE_RELATION":
      return t("ui.dev.clients.relationships.remove_title", "관계 삭제");
    case "DELETE_CLIENT":
      return t("ui.dev.clients.recent_changes.guide.delete", "앱 삭제");
    default:
      return action;
  }
}

function getRecentClientFieldLabel(key: string) {
  switch (key) {
    case "name":
      return t("ui.dev.clients.table.application", "Application");
    case "type":
      return t("ui.dev.clients.table.type", "Type");
    case "status":
      return t("ui.dev.clients.table.status", "Status");
    case "relation":
      return t("ui.dev.clients.relationships.relation", "관계");
    case "subject":
      return t("ui.dev.clients.relationships.subject", "주체");
    case "client_secret":
      return t(
        "ui.dev.clients.details.credentials.client_secret",
        "클라이언트 시크릿",
      );
    default:
      return key;
  }
}

export function buildRecentClientChangeDetails(
  action: string,
  details: AuditDetails,
) {
  const before = isRecord(details.before) ? details.before : {};
  const after = isRecord(details.after) ? details.after : {};

  if (action === "ROTATE_SECRET") {
    return [
      {
        label: getRecentClientFieldLabel("client_secret"),
        value: t("msg.dev.clients.details.secret_rotated", "재발급"),
      },
    ];
  }

  if (action === "ADD_RELATION" || action === "REMOVE_RELATION") {
    const source = action === "ADD_RELATION" ? after : before;
    return [
      ...(source.relation
        ? [
            {
              label: getRecentClientFieldLabel("relation"),
              value: formatAuditValue(source.relation),
            },
          ]
        : []),
      ...(source.subject
        ? [
            {
              label: getRecentClientFieldLabel("subject"),
              value: formatAuditValue(source.subject),
            },
          ]
        : []),
    ];
  }

  const keys = Array.from(
    new Set([...Object.keys(before), ...Object.keys(after)]),
  );

  const changes = keys
    .map((key) => {
      const beforeValue = before[key];
      const afterValue = after[key];

      if (action !== "CREATE_CLIENT" && action !== "DELETE_CLIENT") {
        if (JSON.stringify(beforeValue) === JSON.stringify(afterValue)) {
          return null;
        }
      }

      const label = getRecentClientFieldLabel(key);
      if (action === "CREATE_CLIENT") {
        if (afterValue === undefined) {
          return null;
        }
        return { label, value: formatAuditValue(afterValue) };
      }
      if (action === "DELETE_CLIENT") {
        if (beforeValue === undefined) {
          return null;
        }
        return { label, value: formatAuditValue(beforeValue) };
      }
      if (beforeValue === undefined && afterValue === undefined) {
        return null;
      }
      if (beforeValue === undefined) {
        return { label, value: formatAuditValue(afterValue) };
      }
      if (afterValue === undefined) {
        return { label, value: formatAuditValue(beforeValue) };
      }
      return {
        label,
        value: `${formatAuditValue(beforeValue)} → ${formatAuditValue(afterValue)}`,
      };
    })
    .filter((item): item is { label: string; value: string } => Boolean(item));

  return changes.slice(0, 3);
}

export function buildRecentClientChanges(
  auditLogs: DevAuditLog[],
  clients: ClientSummary[],
) {
  const clientNameById = new Map(
    clients.map((client) => [client.id, client.name || client.id]),
  );

  return auditLogs
    .map((item) => {
      const details = parseAuditDetails(item.details);
      const action = details.action || "";
      const clientId = String(details.target_id || "");
      if (!recentClientActions.has(action) || !clientId) {
        return null;
      }
      return {
        eventId: item.event_id,
        clientId,
        clientName: clientNameById.get(clientId) || clientId,
        actorId: resolveAuditActor(
          item as Pick<CommonAuditLog, "user_id">,
          details,
        ),
        action,
        actionLabel: getRecentClientActionLabel(action),
        timestamp: item.timestamp,
        detailLabels: buildRecentClientChangeDetails(action, details),
      } satisfies RecentClientChange;
    })
    .filter((item): item is RecentClientChange => Boolean(item))
    .sort(
      (left, right) =>
        new Date(right.timestamp).getTime() -
        new Date(left.timestamp).getTime(),
    );
}
