import type { CdcGpsfMeetingRequestRow } from "@/features/cdc-gpsf/meeting-requests/cdc-gpsf-meeting-request-data";
import type {
  ApiIssue,
  ApiMeetingRequest,
  ApiStakeholder,
  ApiWorkingGroup,
} from "@/features/cdc-gpsf/meeting-requests/service/cdc-gpsf-meeting-request-service";

export type CdcGpsfMeetingRequestRowWithApi = CdcGpsfMeetingRequestRow & {
  title?: string;
  workingGroupId?: number | null;
  governmentAgencyId?: number | null;
  meetingMonthYear?: string;
  meetingRequestLetter?: string | null;
  description?: string;
  issueIds?: number[];
  rawIssues?: ApiIssue[];
  issues?: ApiIssue[];
};

export type CdcGpsfMeetingRequestFilters = {
  workingGroupFilter?: string[];
  governmentAgencyFilter?: string[];
  statusFilter?: string[];
  meetingDateFilter?: string[];
};

export function hasValidMeetingRequestId(
  item: unknown,
): item is ApiMeetingRequest {
  if (!item || typeof item !== "object") return false;

  const id = (item as { id?: unknown }).id;

  return typeof id === "number" && Number.isFinite(id);
}

export function formatMeetingRequestMonthYear(value?: string) {
  if (!value) return "-";

  const date = new Date(value);

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

  return date.toLocaleDateString("en-US", {
    month: "short",
    year: "numeric",
  });
}

export function getMeetingRequestFileName(path?: string | null) {
  if (!path) return "-";

  const parts = String(path).split("/");
  return parts[parts.length - 1] || path;
}

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

  const plainText = value
    .replace(/<style[\s\S]*?<\/style>/gi, "")
    .replace(/<script[\s\S]*?<\/script>/gi, "")
    .replace(/<br\s*\/?>/gi, " ")
    .replace(/<\/p>/gi, " ")
    .replace(/<\/div>/gi, " ")
    .replace(/<\/li>/gi, " ")
    .replace(/<[^>]+>/g, "")
    .replace(/&nbsp;/gi, " ")
    .replace(/&amp;/gi, "&")
    .replace(/&lt;/gi, "<")
    .replace(/&gt;/gi, ">")
    .replace(/&quot;/gi, '"')
    .replace(/&#39;/gi, "'")
    .replace(/\s+/g, " ")
    .trim();

  return plainText || "-";
}

export function resolveWorkingGroupForMeetingRequest(
  item: ApiMeetingRequest,
  workingGroups: ApiWorkingGroup[],
): ApiWorkingGroup | null {
  const agencies =
    item.governmentAgencies
      ?.map((agencyRequest) => agencyRequest.stakeholder)
      .filter((stakeholder): stakeholder is ApiStakeholder =>
        Boolean(stakeholder),
      ) ?? [];

  const directWorkingGroup = agencies.find(
    (agency) =>
      agency.stakeholderTypeId === 2 ||
      agency.stakeholderType?.name?.toLowerCase().includes("working"),
  );

  if (directWorkingGroup) {
    return directWorkingGroup as ApiWorkingGroup;
  }

  for (const agency of agencies) {
    const agencyId = Number(agency.id);
    const agencyRelatedStakeholderId = Number(agency.relatedStakeholderId);

    const found = workingGroups.find((workingGroup) => {
      const workingGroupId = Number(workingGroup.id);
      const workingGroupRelatedStakeholderId = Number(
        workingGroup.relatedStakeholderId,
      );

      return (
        workingGroupRelatedStakeholderId === agencyId ||
        workingGroupId === agencyRelatedStakeholderId
      );
    });

    if (found) return found;
  }

  return null;
}

export function mapMeetingRequestToRow(
  item: ApiMeetingRequest,
  workingGroups: ApiWorkingGroup[],
): CdcGpsfMeetingRequestRowWithApi {
  const firstAgency = item.governmentAgencies?.[0]?.stakeholder;
  const workingGroup = resolveWorkingGroupForMeetingRequest(item, workingGroups);
  const rowIssues = item.issues || [];

  return {
    id: item.id,
    title: item.title || "",
    workingGroup: workingGroup?.name || "-",
    workingGroupId: workingGroup?.id ?? null,
    meetingDescription: htmlToPlainText(item.description),
    description: item.description || "",
    issuesCount: rowIssues.length,
    issueIds: rowIssues.map((issue) => issue.id),
    rawIssues: rowIssues,
    issues: rowIssues,
    meetingStatus: item.status || "Drafted",
    meetingDate: item.createdAt || "-",
    meetingMonthYear: formatMeetingRequestMonthYear(item.createdAt),
    governmentAgency: firstAgency?.name || "-",
    governmentAgencyId: firstAgency?.id ?? null,
    governmentAgencyLogo: firstAgency?.logo || null,
    meetingRequest: item.meetingRequestLetter || "",
    meetingRequestLetter: item.meetingRequestLetter || "",
  };
}

export function buildMeetingRequestRows(
  data: ApiMeetingRequest[],
  workingGroups: ApiWorkingGroup[],
  filters: CdcGpsfMeetingRequestFilters = {},
): CdcGpsfMeetingRequestRowWithApi[] {
  const {
    workingGroupFilter = [],
    governmentAgencyFilter = [],
    statusFilter = [],
    meetingDateFilter = [],
  } = filters;

  const mappedRows = data
    .filter((item) => hasValidMeetingRequestId(item))
    .map((item) => mapMeetingRequestToRow(item, workingGroups));

  let filteredRows = mappedRows;

  if (workingGroupFilter.length > 0) {
    filteredRows = filteredRows.filter((row) => {
      if (row.workingGroupId) {
        return workingGroupFilter.includes(String(row.workingGroupId));
      }

      return workingGroupFilter.includes(row.workingGroup);
    });
  }

  if (governmentAgencyFilter.length > 0) {
    filteredRows = filteredRows.filter((row) => {
      if (row.governmentAgencyId) {
        return governmentAgencyFilter.includes(String(row.governmentAgencyId));
      }

      return governmentAgencyFilter.includes(row.governmentAgency);
    });
  }

  if (statusFilter.length > 0) {
    filteredRows = filteredRows.filter((row) =>
      statusFilter.includes(row.meetingStatus),
    );
  }

  if (meetingDateFilter.length > 0) {
    filteredRows = filteredRows.filter((row) =>
      meetingDateFilter.includes(row.meetingMonthYear || "-"),
    );
  }

  return filteredRows;
}
