import { z } from "zod";
import { ticketSchema, ticketStatusSchema, ticketWithDetailsSchema } from "@/lib/schemas/ticket";

type NormalizedTicketStatus = z.infer<typeof ticketStatusSchema>;

const STATUS_MAP: Record<string, NormalizedTicketStatus> = {
  NEW: "PENDING",
  PENDING: "PENDING",
  OPEN: "AWAITING_ATTENDANCE",
  AWAITING_ATTENDANCE: "AWAITING_ATTENDANCE",
  ON_HOLD: "PAUSED",
  PAUSED: "PAUSED",
  RESOLVED: "RESOLVED",
  CLOSED: "RESOLVED",
};

function normalizeTicketStatus(status: unknown): NormalizedTicketStatus {
  if (typeof status !== "string") return "PENDING";
  const normalized = STATUS_MAP[status.toUpperCase()];
  return normalized ?? "PENDING";
}

// Server shapes: datas como number (epoch ms) e alguns nullables
// Relaxamos email/urls no shape do servidor para evitar que payloads parciais quebrem o app.
const serverUserSchema = z.object({
  id: z.string(),
  name: z.string(),
  email: z.string().optional(),
  avatarUrl: z.string().optional(),
  teams: z.array(z.string()).optional(),
});

const serverTicketSchema = z.object({
  id: z.string(),
  reference: z.number(),
  tenantId: z.string(),
  subject: z.string(),
  summary: z.string().optional().nullable(),
  status: z.string(),
  priority: z.string(),
  channel: z.string(),
  queue: z.string().nullable(),
  requester: serverUserSchema,
  assignee: serverUserSchema.nullable(),
  slaPolicy: z.any().nullable().optional(),
  dueAt: z.number().nullable().optional(),
  firstResponseAt: z.number().nullable().optional(),
  resolvedAt: z.number().nullable().optional(),
  updatedAt: z.number(),
  createdAt: z.number(),
  tags: z.array(z.string()).default([]).optional(),
  lastTimelineEntry: z.string().nullable().optional(),
  metrics: z.any().nullable().optional(),
  category: z
    .object({
      id: z.string(),
      name: z.string(),
    })
    .nullable()
    .optional(),
  subcategory: z
    .object({
      id: z.string(),
      name: z.string(),
      categoryId: z.string().optional(),
    })
    .nullable()
    .optional(),
  workSummary: z
    .object({
      totalWorkedMs: z.number(),
      internalWorkedMs: z.number().optional(),
      externalWorkedMs: z.number().optional(),
      activeSession: z
        .object({
          id: z.string(),
          agentId: z.string(),
          startedAt: z.number(),
        })
        .nullable(),
    })
    .nullable()
    .optional(),
});

const serverAttachmentSchema = z.object({
  id: z.any(),
  name: z.string(),
  size: z.number().optional(),
  url: z.string().url().optional(),
});

const serverCommentSchema = z.object({
  id: z.string(),
  author: serverUserSchema,
  visibility: z.string(),
  body: z.string(),
  attachments: z.array(serverAttachmentSchema).default([]).optional(),
  createdAt: z.number(),
  updatedAt: z.number(),
});

const serverEventSchema = z.object({
  id: z.string(),
  type: z.string(),
  payload: z.any().optional(),
  createdAt: z.number(),
});

const serverCustomFieldValueSchema = z.object({
  label: z.string(),
  type: z.string(),
  value: z.any().optional(),
  displayValue: z.string().optional(),
});

const serverTicketWithDetailsSchema = serverTicketSchema.extend({
  description: z.string().optional().nullable(),
  customFields: z.record(z.string(), serverCustomFieldValueSchema).optional(),
  timeline: z.array(serverEventSchema),
  comments: z.array(serverCommentSchema),
  company: z
    .object({ id: z.string(), name: z.string(), isAvulso: z.boolean().optional() })
    .optional()
    .nullable(),
});

export function mapTicketFromServer(input: unknown) {
  const s = serverTicketSchema.parse(input);
  const ui = {
    ...s,
    status: normalizeTicketStatus(s.status),
    category: s.category ?? undefined,
    subcategory: s.subcategory ?? undefined,
    lastTimelineEntry: s.lastTimelineEntry ?? undefined,
    updatedAt: new Date(s.updatedAt),
    createdAt: new Date(s.createdAt),
    dueAt: s.dueAt ? new Date(s.dueAt) : null,
    firstResponseAt: s.firstResponseAt ? new Date(s.firstResponseAt) : null,
    resolvedAt: s.resolvedAt ? new Date(s.resolvedAt) : null,
    workSummary: s.workSummary
      ? {
          totalWorkedMs: s.workSummary.totalWorkedMs,
          internalWorkedMs: s.workSummary.internalWorkedMs ?? 0,
          externalWorkedMs: s.workSummary.externalWorkedMs ?? 0,
          activeSession: s.workSummary.activeSession
            ? {
                ...s.workSummary.activeSession,
                startedAt: new Date(s.workSummary.activeSession.startedAt),
              }
            : null,
        }
      : undefined,
  };
  return ui as unknown as z.infer<typeof ticketSchema>;
}

export function mapTicketsFromServerList(arr: unknown[]) {
  return arr.map(mapTicketFromServer);
}

export function mapTicketWithDetailsFromServer(input: unknown) {
  const s = serverTicketWithDetailsSchema.parse(input);
  const customFields = Object.entries(s.customFields ?? {}).reduce<
    Record<string, { label: string; type: string; value?: unknown; displayValue?: string }>
  >(
    (acc, [key, value]) => {
      let parsedValue: unknown = value.value;
      if (value.type === "date" && typeof value.value === "number") {
        parsedValue = new Date(value.value);
      }
      acc[key] = {
        label: value.label,
        type: value.type,
        value: parsedValue,
        displayValue: value.displayValue,
      };
      return acc;
    },
    {}
  );
  const ui = {
    ...s,
    customFields,
    status: normalizeTicketStatus(s.status),
    category: s.category ?? undefined,
    subcategory: s.subcategory ?? undefined,
    lastTimelineEntry: s.lastTimelineEntry ?? undefined,
    updatedAt: new Date(s.updatedAt),
    createdAt: new Date(s.createdAt),
    dueAt: s.dueAt ? new Date(s.dueAt) : null,
    firstResponseAt: s.firstResponseAt ? new Date(s.firstResponseAt) : null,
    resolvedAt: s.resolvedAt ? new Date(s.resolvedAt) : null,
    company: s.company ? { id: s.company.id, name: s.company.name, isAvulso: s.company.isAvulso ?? false } : undefined,
    timeline: s.timeline.map((e) => ({ ...e, createdAt: new Date(e.createdAt) })),
    comments: s.comments.map((c) => ({
      ...c,
      createdAt: new Date(c.createdAt),
      updatedAt: new Date(c.updatedAt),
    })),
    workSummary: s.workSummary
      ? {
          totalWorkedMs: s.workSummary.totalWorkedMs,
          activeSession: s.workSummary.activeSession
            ? {
                ...s.workSummary.activeSession,
                startedAt: new Date(s.workSummary.activeSession.startedAt),
              }
            : null,
        }
      : undefined,
  };
  return ui as unknown as z.infer<typeof ticketWithDetailsSchema>;
}
