import type { UploadedFileMetadata } from "@/lib/document-file";
import type {
  MeetingRequestGovernmentAgency,
  MeetingRequestIssue,
  MeetingRequestIssueAgency,
} from "@/features/ministry/meeting-request/meeting-request-data";

export type MeetingCalendarStatus =
  | "Draft"
  | "Scheduled"
  | "Submitted"
  | "Completed";

const CAMBODIA_TIME_ZONE = "Asia/Phnom_Penh";

export type MeetingCalendarRow = {
  id: number;
  meetingSummaryId: number | null;
  title: string;
  workingGroup: string;
  description: string;
  issueCount: number;
  meetingRequest: string;
  meetingDate: string;
  dateKey: string | null;
  timeRange: string;
  participantCount: number;
  status: MeetingCalendarStatus;
  year: number;
};

export type MeetingCalendarFilters = {
  status: string[];
  year: string[];
  issueCount: string[];
};

export type MeetingCalendarApiGuest = {
  email?: string | null;
  userId?: number | null;
  user?: {
    id: number;
    name?: string | null;
    email?: string | null;
    avatar?: string | null;
    position?: string | null;
  } | null;
};

export type MeetingCalendarApiIssue = {
  id?: number | null;
  title?: string | null;
  issue?: string | null;
  description?: string | null;
  recommendation?: string | null;
  attachment?: string | null;
  status?: string | null;
  issueStatus?: { name?: string | null } | null;
  category?: { name?: string | null } | string | null;
  primaryAgency?: string | null;
  primaryAgencyLogo?: string | null;
  secondAgency?: string | null;
  secondAgencyLogo?: string | null;
  thirdAgency?: string | null;
  thirdAgencyLogo?: string | null;
  fourthAgency?: string | null;
  fourthAgencyLogo?: string | null;
  fifthAgency?: string | null;
  fifthAgencyLogo?: string | null;
  governmentAgencies?: MeetingRequestIssueAgency[] | null;
  createdAt?: string | null;
};

export type MeetingCalendarApiGovernmentAgency = {
  stakeholderId?: number | null;
  stakeholder?: {
    id?: number | null;
    name?: string | null;
    logo?: string | null;
  } | null;
};

export type MeetingCalendarApiMeeting = {
  id: number;
  meetingSummaryId?: number | null;
  title?: string | null;
  description?: string | null;
  meetingDate?: string | null;
  startTime?: string | null;
  endTime?: string | null;
  location?: string | null;
  documentReference?: UploadedFileMetadata | null;
  status?: string | null;
  workingGroupName?: string | null;
  issueCount?: number | null;
  guests?: MeetingCalendarApiGuest[] | null;
  meetingRequest?: {
    id?: number | null;
    title?: string | null;
    status?: string | null;
    meetingRequestLetter?: string | null;
    submittedBy?: string | null;
    requestedBy?: string | null;
    requestedDate?: string | null;
    privateSectorWG?: string | null;
    issues?: MeetingCalendarApiIssue[] | null;
    governmentAgencies?: MeetingCalendarApiGovernmentAgency[] | null;
  } | null;
};

export type MeetingCalendarApiListResponse = {
  items: MeetingCalendarApiMeeting[];
  meta?: {
    page: number;
    limit: number;
    total: number;
    totalPages: number;
  };
};

function getApiOrigin() {
  const raw =
    process.env.NEXT_PUBLIC_API_URL ??
    process.env.NEXT_PUBLIC_API_BASE_URL ??
    "http://localhost:3001/api/v1";

  return raw.replace(/\/api\/v\d+\/?$/, "").replace(/\/+$/, "");
}

export function resolveMeetingAssetUrl(path?: string | null) {
  if (!path) return null;

  const cleanPath = path.trim();

  if (!cleanPath) return null;

  if (/^(https?:)?\/\//i.test(cleanPath) || cleanPath.startsWith("data:")) {
    return cleanPath;
  }

  return `${getApiOrigin()}${cleanPath.startsWith("/") ? cleanPath : `/${cleanPath}`}`;
}

type AgencySlot = {
  name: string;
  logo: string | null;
};

function getIssueAgencySlot(
  issue: MeetingCalendarApiIssue,
  meetingRequestAgencies: MeetingRequestGovernmentAgency[],
  agencyOrder: number,
): AgencySlot {
  const issueAgency = issue.governmentAgencies?.find(
    (agency) => agency.agencyOrder === agencyOrder,
  );

  const flatName = [
    "",
    "primaryAgency",
    "secondAgency",
    "thirdAgency",
    "fourthAgency",
    "fifthAgency",
  ][agencyOrder] as keyof MeetingCalendarApiIssue;
  const flatLogo = [
    "",
    "primaryAgencyLogo",
    "secondAgencyLogo",
    "thirdAgencyLogo",
    "fourthAgencyLogo",
    "fifthAgencyLogo",
  ][agencyOrder] as keyof MeetingCalendarApiIssue;

  const primaryFallback = agencyOrder === 1 ? meetingRequestAgencies[0] : null;
  const name =
    issueAgency?.stakeholder?.name ??
    (issue[flatName] as string | null | undefined) ??
    primaryFallback?.name ??
    (agencyOrder === 1 ? "-" : "Not Uploaded");
  const logo = resolveMeetingAssetUrl(
    issueAgency?.stakeholder?.logo ??
      (issue[flatLogo] as string | null | undefined) ??
      primaryFallback?.logo,
  );

  return { name, logo };
}

export function mapMeetingCalendarIssues(
  issues: MeetingCalendarApiIssue[] | null | undefined,
  meetingRequestAgencies: MeetingRequestGovernmentAgency[] = [],
): MeetingRequestIssue[] {
  return (issues ?? []).map((issue, index) => {
    const agencies = [1, 2, 3, 4, 5].map((agencyOrder) =>
      getIssueAgencySlot(issue, meetingRequestAgencies, agencyOrder),
    );
    const category =
      typeof issue.category === "string"
        ? issue.category
        : issue.category?.name;

    return {
      id: issue.id ?? index + 1,
      issue: issue.issue ?? issue.title ?? "-",
      title: issue.title ?? issue.issue ?? "-",
      category: category ?? "-",
      description: issue.description ?? "-",
      recommendation: issue.recommendation ?? "-",
      attachment: resolveMeetingAssetUrl(issue.attachment),
      status: issue.status ?? issue.issueStatus?.name ?? "-",
      createdAt: issue.createdAt,
      governmentAgencies: issue.governmentAgencies ?? null,
      primaryAgency: agencies[0].name,
      primaryAgencyLogo: agencies[0].logo,
      secondAgency: agencies[1].name,
      secondAgencyLogo: agencies[1].logo,
      thirdAgency: agencies[2].name,
      thirdAgencyLogo: agencies[2].logo,
      fourthAgency: agencies[3].name,
      fourthAgencyLogo: agencies[3].logo,
      fifthAgency: agencies[4].name,
      fifthAgencyLogo: agencies[4].logo,
    };
  });
}

export function getMeetingSummaryAction(meetingSummaryId: number | null) {
  if (meetingSummaryId) {
    return {
      label: "View Meeting Summary",
      path: `/ministry/meeting-summary/${meetingSummaryId}`,
    };
  }

  return {
    label: "Create Meeting Summary",
    path: null,
  };
}

const monthNumbers: Record<string, number> = {
  January: 1,
  February: 2,
  March: 3,
  April: 4,
  May: 5,
  June: 6,
  July: 7,
  August: 8,
  September: 9,
  October: 10,
  November: 11,
  December: 12,
};

export const defaultMeetingCalendarFilters: MeetingCalendarFilters = {
  status: [],
  year: [],
  issueCount: [],
};

function stripHtml(value?: string | null) {
  if (!value) return "-";

  return value
    .replace(/<[^>]*>/g, " ")
    .replace(/&amp;/g, "&")
    .replace(/&nbsp;/g, " ")
    .replace(/&quot;/g, '"')
    .replace(/&#39;/g, "'")
    .replace(/\s+/g, " ")
    .trim();
}

function getApiMeetingRequestPath(meeting: MeetingCalendarApiMeeting) {
  const documentReference = meeting.documentReference?.path?.trim();
  if (documentReference) {
    return documentReference;
  }

  const letter = meeting.meetingRequest?.meetingRequestLetter?.trim();
  if (letter) {
    return letter;
  }

  return "";
}

function formatApiTime(value?: string | null) {
  if (!value) return "-";

  const date = new Date(value);

  if (Number.isNaN(date.getTime())) return "-";

  return new Intl.DateTimeFormat("en-US", {
    hour: "numeric",
    minute: "2-digit",
    hour12: true,
    timeZone: "UTC",
  }).format(date);
}

function formatApiTimeRange(startValue?: string | null, endValue?: string | null) {
  const startTime = formatApiTime(startValue);
  const endTime = formatApiTime(endValue);

  if (startTime === "-" || endTime === "-") {
    return "-";
  }

  return `${startTime} - ${endTime}`;
}

function getApiDateKey(value?: string | null) {
  if (!value) return null;

  const date = new Date(value);

  if (Number.isNaN(date.getTime())) return null;

  return formatDateKey(date);
}

function getApiYear(value?: string | null) {
  if (!value) return new Date().getUTCFullYear();

  const date = new Date(value);

  if (Number.isNaN(date.getTime())) return new Date().getUTCFullYear();

  return date.getUTCFullYear();
}

function getApiWorkingGroupName(meeting: MeetingCalendarApiMeeting) {
  const workingGroupName = meeting.workingGroupName?.trim();

  return workingGroupName || "-";
}

function getApiIssueCount(meeting: MeetingCalendarApiMeeting) {
  return meeting.issueCount ?? 0;
}

function getApiMeetingStatus(
  meeting: MeetingCalendarApiMeeting,
): MeetingCalendarStatus {
  if (meeting.status === "DRAFT" || meeting.status === "Drafted") {
    return "Draft";
  }

  if (meeting.status === "SCHEDULED" || meeting.status === "Scheduled") {
    return "Scheduled";
  }

  if (meeting.status === "COMPLETED" || meeting.status === "Completed") {
    return "Completed";
  }

  return "Submitted";
}

export function mapApiMeetingToCalendarRow(
  meeting: MeetingCalendarApiMeeting,
): MeetingCalendarRow {
  return {
    id: meeting.id,
    meetingSummaryId: meeting.meetingSummaryId ?? null,
    title: meeting.title || "-",
    workingGroup: getApiWorkingGroupName(meeting),
    description: stripHtml(meeting.description),
    issueCount: getApiIssueCount(meeting),
    meetingRequest: getApiMeetingRequestPath(meeting),
    meetingDate: meeting.meetingDate || "-",
    dateKey: getApiDateKey(meeting.meetingDate),
    timeRange: formatApiTimeRange(meeting.startTime, meeting.endTime),
    participantCount: meeting.guests?.length ?? 0,
    status: getApiMeetingStatus(meeting),
    year: getApiYear(meeting.meetingDate),
  };
}

export function filterMeetingCalendarRows(
  rows: MeetingCalendarRow[],
  filters: MeetingCalendarFilters,
) {
  return rows.filter((row) => {
    const matchesStatus =
      filters.status.length === 0 || filters.status.includes(row.status);
    const matchesYear =
      filters.year.length === 0 || filters.year.includes(String(row.year));
    const matchesIssueCount =
      filters.issueCount.length === 0 ||
      filters.issueCount.includes(String(row.issueCount));

    return matchesStatus && matchesYear && matchesIssueCount;
  });
}

function formatDateKey(date: Date) {
  const year = date.getUTCFullYear();
  const month = String(date.getUTCMonth() + 1).padStart(2, "0");
  const day = String(date.getUTCDate()).padStart(2, "0");

  return `${year}-${month}-${day}`;
}

export function getTodayDateKey() {
  return getCambodiaDateKey(new Date());
}

function getCambodiaDateKey(date: Date) {
  const parts = new Intl.DateTimeFormat("en-US", {
    timeZone: CAMBODIA_TIME_ZONE,
    year: "numeric",
    month: "2-digit",
    day: "2-digit",
  }).formatToParts(date);

  const year = parts.find((part) => part.type === "year")?.value;
  const month = parts.find((part) => part.type === "month")?.value;
  const day = parts.find((part) => part.type === "day")?.value;

  return `${year}-${month}-${day}`;
}

export function canEditMeetingByDate(
  meetingDateKey: string | null,
  todayDateKey = getTodayDateKey(),
) {
  return !meetingDateKey || meetingDateKey >= todayDateKey;
}

export function canCreateMeetingSummaryByDate(
  meetingDateKey: string | null,
  todayDateKey = getTodayDateKey(),
) {
  return Boolean(meetingDateKey && meetingDateKey < todayDateKey);
}

export function canEditMeetingCalendarRow(
  row: Pick<MeetingCalendarRow, "status" | "dateKey" | "meetingSummaryId">,
  todayDateKey = getTodayDateKey(),
) {
  return (
    row.status === "Draft" ||
    canEditMeetingByDate(row.dateKey, todayDateKey) ||
    (row.status === "Scheduled" && row.meetingSummaryId === null)
  );
}

export function canUseMeetingSummaryAction(
  row: Pick<MeetingCalendarRow, "status" | "dateKey" | "meetingSummaryId">,
  todayDateKey = getTodayDateKey(),
) {
  if (row.meetingSummaryId !== null) {
    return true;
  }

  return (
    row.status === "Scheduled" &&
    canCreateMeetingSummaryByDate(row.dateKey, todayDateKey)
  );
}

export function getCalendarMonthFromDate(date = new Date()) {
  return {
    year: date.getUTCFullYear(),
    monthIndex: date.getUTCMonth(),
  };
}

export function getCalendarMonthFromRows(rows: MeetingCalendarRow[]) {
  const today = new Date();
  const currentMonth = getCalendarMonthFromDate(today);
  const currentMonthPrefix = `${currentMonth.year}-${String(currentMonth.monthIndex + 1).padStart(2, "0")}`;

  const datedRows = rows
    .map((row) => row.dateKey ?? getMeetingDateKey(row.meetingDate))
    .filter((dateKey): dateKey is string => Boolean(dateKey))
    .sort();

  if (datedRows.length === 0) {
    return currentMonth;
  }

  if (datedRows.some((dateKey) => dateKey.startsWith(currentMonthPrefix))) {
    return currentMonth;
  }

  const todayKey = getTodayDateKey();
  const nearestDateKey =
    datedRows.find((dateKey) => dateKey >= todayKey) ?? datedRows[datedRows.length - 1];
  const [year, month] = nearestDateKey.split("-").map(Number);

  if (!year || !month) {
    return currentMonth;
  }

  return {
    year,
    monthIndex: month - 1,
  };
}

export function getMeetingCalendarYears(rows: MeetingCalendarRow[]) {
  return [...new Set(rows.map((row) => String(row.year)))].sort(
    (left, right) => Number(right) - Number(left),
  );
}

function getMeetingDateKey(meetingDate: string) {
  const [monthName, dayWithComma, year] = meetingDate.split(" ");
  const month = monthNumbers[monthName];
  const day = Number(dayWithComma?.replace(",", ""));

  if (!month || !day || !year) {
    return null;
  }

  return `${year}-${String(month).padStart(2, "0")}-${String(day).padStart(2, "0")}`;
}
