/**
 * Khi có ticketId: WO điều khiển trạng thái phiếu (InProgress / Resolved / Closed),
 * kể cả hạ trạng thái phiếu nếu WO quay lại «Đang thực hiện». Draft / Approved / Cancelled không đổi phiếu.
 * Tiến độ % chỉ tính từ WO (tránh checklist 100% cũ khi WO vẫn Đang thực hiện).
 */
import { dataService } from '../services/dataService';
import { TicketStatus, type IWorkOrder, type ITicket, type IUser } from '../types';

export function normalizeTicketIdRef(ref: unknown): string | undefined {
  if (ref === undefined || ref === null || ref === '') return undefined;
  if (typeof ref === 'object' && ref !== null) {
    const anyRef = ref as any;
    if (anyRef._id !== undefined && anyRef._id !== null) return String(anyRef._id);
    if (anyRef.id !== undefined && anyRef.id !== null) return String(anyRef.id);
    if (anyRef.ticketCode !== undefined && anyRef.ticketCode !== null) return String(anyRef.ticketCode);
    if (anyRef.code !== undefined && anyRef.code !== null) return String(anyRef.code);
  }
  return String(ref);
}

export function resolveTicketForWorkOrder(
  ticketRef: unknown,
  tickets: ITicket[],
): { id: string; code: string; title?: string } | null {
  const id = normalizeTicketIdRef(ticketRef);
  if (!id) return null;
  if (typeof ticketRef === 'object' && ticketRef !== null && 'code' in ticketRef) {
    const o = ticketRef as { code?: string; title?: string };
    return { id, code: o.code || id, title: o.title };
  }
  const t = tickets.find((x) => String(x._id) === id || x.code === id);
  if (t) return { id: String(t._id), code: t.code, title: t.title };
  return { id, code: id };
}

/**
 * Trạng thái phiếu backend (Open | InProgress | Resolved | Closed) cần khớp với WO.
 * null = không gọi API (Draft / Cancelled).
 */
export function targetTicketStatusFromWorkOrder(woStatus: string): TicketStatus | null {
  switch (woStatus) {
    case 'Draft':
    case 'Approved':
    case 'Cancelled':
      return null;
    case 'In Progress':
    case 'InProgress':
      return TicketStatus.IN_PROGRESS;
    case 'Completed':
      return TicketStatus.RESOLVED;
    case 'Verified':
      return TicketStatus.CLOSED;
    default:
      return null;
  }
}

/** Map trạng thái UI (Assigned, PendingParts) về giá trị tương đương khi so sánh với target backend. */
function ticketStatusComparable(status: TicketStatus | string): TicketStatus {
  const s = String(status) as TicketStatus;
  if (s === TicketStatus.ASSIGNED) return TicketStatus.OPEN;
  if (s === TicketStatus.PENDING_PARTS) return TicketStatus.IN_PROGRESS;
  return s;
}

/** Tiến độ % chỉ từ WO — checklistProgress có thể còn 100 sau khi đổi lại «Đang thực hiện». */
export function baseWorkOrderProgressPercent(wo: IWorkOrder): number {
  const raw = wo.checklistProgress ?? 0;

  if (wo.status === 'Completed' || wo.status === 'Verified') {
    return 100;
  }

  if (wo.status === 'In Progress' || wo.status === 'InProgress') {
    if (raw >= 100) return 55;
    if (raw > 0) return Math.min(raw, 95);
    return 50;
  }

  if (wo.status === 'Approved') {
    if (raw >= 100) return 20;
    return raw > 0 ? Math.min(raw, 40) : 12;
  }

  if (raw >= 100) return 8;
  return raw > 0 ? Math.min(raw, 30) : 4;
}

export function getLinkedWorkOrderProgressPercent(wo: IWorkOrder): number {
  return Math.round(baseWorkOrderProgressPercent(wo));
}

export async function syncTicketStatusFromWorkOrder(
  wo: IWorkOrder,
  ticketsCache: ITicket[],
  projectId: string | undefined,
): Promise<boolean> {
  const tid = normalizeTicketIdRef(wo.ticketId);
  const target = targetTicketStatusFromWorkOrder(String(wo.status));
  if (!tid || !projectId || !target) return false;

  let ticket = ticketsCache.find((t) => String(t._id) === tid || t.code === tid);
  if (!ticket) {
    const fresh = await dataService.getTickets(projectId);
    ticket = fresh.find((t) => String(t._id) === tid || t.code === tid);
  }
  if (!ticket) return false;

  const current = ticketStatusComparable(ticket.status);
  if (current === target) return false;

  await dataService.updateTicket({ ...ticket, status: target });
  return true;
}

export function aggregateTicketAssigneesFromWorkOrders(
  ticketId: string,
  ticketCode: string | undefined,
  workOrders: IWorkOrder[],
  users: IUser[],
): string[] {
  const assignedIds = new Set<string>();
  const tid = String(ticketId);
  const code = ticketCode ? String(ticketCode) : '';

  const linkedWOs = workOrders.filter(wo => {
    const wtid = normalizeTicketIdRef(wo.ticketId);
    return wtid !== undefined && (wtid === tid || wtid === code);
  });

  linkedWOs.forEach(wo => {
    // 1. From assignedTechnicianId (robust unwrapping)
    if (wo.assignedTechnicianId) {
      if (Array.isArray(wo.assignedTechnicianId)) {
        wo.assignedTechnicianId.forEach(id => {
          if (id) {
            const cleanId = typeof id === 'object' && id !== null ? ((id as any)._id || (id as any).id) : id;
            if (cleanId) assignedIds.add(String(cleanId));
          }
        });
      } else {
        const id = wo.assignedTechnicianId;
        const cleanId = typeof id === 'object' && id !== null ? ((id as any)._id || (id as any).id) : id;
        if (cleanId) assignedIds.add(String(cleanId));
      }
    }
    // 2. From assignedTo (which might be comma-separated names or IDs)
    if (wo.assignedTo) {
      if (typeof wo.assignedTo === 'string') {
        const parts = wo.assignedTo.split(',').map(p => p.trim()).filter(Boolean);
        parts.forEach(part => {
          const user = users.find(u => u._id === part || u.name === part);
          if (user) {
            assignedIds.add(user._id);
          } else {
            // Robust fallback: if part is a 24-character hex ID, or doesn't have spaces (highly likely an ID),
            // add it directly to our assignees set without requiring name lookup
            const looksLikeId = /^[0-9a-fA-F]{24}$/.test(part) || !part.includes(' ');
            if (looksLikeId) {
              assignedIds.add(part);
            }
          }
        });
      }
    }
  });

  return Array.from(assignedIds);
}

export async function syncTicketAssigneeFromWorkOrders(
  ticketIdRef: unknown,
  projectId: string | undefined,
  users: IUser[],
): Promise<boolean> {
  const tid = normalizeTicketIdRef(ticketIdRef);
  if (!tid || !projectId) {
    console.log('[Assignee Sync] Missing ticket ID or project ID:', { tid, projectId });
    return false;
  }

  console.log('[Assignee Sync] Syncing ticket:', tid);

  // Get fresh tickets and work orders for the project
  const [tickets, workOrders] = await Promise.all([
    dataService.getTickets(projectId),
    dataService.getWorkOrders(projectId)
  ]);

  const ticket = tickets.find((t) => String(t._id) === tid || t.code === tid);
  if (!ticket) {
    console.warn('[Assignee Sync] Ticket not found in cached list:', tid);
    return false;
  }

  // Aggregate assignee IDs from linked Work Orders
  const aggregatedIds = aggregateTicketAssigneesFromWorkOrders(ticket._id, ticket.code, workOrders, users);
  console.log('[Assignee Sync] Aggregated assignee IDs from linked WOs:', aggregatedIds);

  // If there are no linked work orders, we don't overwrite the original ticket assignee.
  const linkedWOs = workOrders.filter(wo => {
    const wtid = normalizeTicketIdRef(wo.ticketId);
    return wtid !== undefined && (wtid === String(ticket._id) || wtid === ticket.code);
  });
  if (linkedWOs.length === 0) {
    console.log('[Assignee Sync] No linked work orders for ticket:', tid);
    return false;
  }

  const newAssignedToValue = aggregatedIds.length > 0 ? aggregatedIds.join(',') : '';
  console.log('[Assignee Sync] New assignedTo string to save:', newAssignedToValue);

  // Only update if the value has changed
  if (ticket.assignedTo === newAssignedToValue) {
    console.log('[Assignee Sync] Value has not changed, skipping save');
    return false;
  }

  try {
    await dataService.updateTicket({ ...ticket, assignedTo: newAssignedToValue });
    console.log('[Assignee Sync] Successfully updated ticket assignee to:', newAssignedToValue);
    return true;
  } catch (err) {
    console.error('[Assignee Sync] Failed to update ticket assignee:', err);
    throw err;
  }
}
