export type MeetingCalendarEventColor = "blue" | "green" | "orange" | "dark";

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

export type MeetingCalendarIssue = {
    id: string;
    title: string;
    description: string;
    recommendation?: string;
    category?: string;
    status?: string;
    submittedDate?: string;
    governmentAgency?: string;
    governmentAgencyLogo?: string | null;
};

export type MeetingCalendarEvent = {
    id: string;
    date: string;
    time: string;
    startTime: string;
    endTime: string;
    title: string;
    participants: number;
    color: MeetingCalendarEventColor;
    status: MeetingCalendarStatus;
    submittedDate: string;
    governmentAgency: string;
    governmentAgencyLogo?: string | null;
    documentName: string;
    documentSize: string;
    description: string;
    issues: MeetingCalendarIssue[];
    meetingRequestId?: number | null;
    meetingUpdate?: {
        meetingDate: string;
        meetingTime: string;
        startTime: string;
        endTime: string;
        referenceDocumentName: string;
        referenceDocumentSize: string;
        progressSolutionTitle: string;
        progressSolutionDescription: string;
        solutionIndicatorsTitle: string;
        solutionIndicatorsDescription: string;
    };
};

type ApiMeeting = {
    id: string | number;
    title?: string | null;
    description?: string | null;
    meetingDate?: string | null;
    startTime?: string | null;
    endTime?: string | null;
    location?: string | null;
    documentReference?: string | null;
    status?: string | null;
    meetingRequestId?: string | number | null;
    createdAt?: string | null;
    user?: {
        name?: string | null;
        organization?: string | null;
    } | null;
    // បន្ថែម Field នេះដើម្បីឱ្យត្រូវនឹង JSON
    governmentAgencies?: Array<{
        stakeholder?: {
            name?: string | null;
            logo?: string | null;
        } | null;
        name?: string | null;
        logo?: string | null;
    }> | null;
    meetingRequest?: {
        id?: string | number | null;
        governmentAgencies?: Array<{
            stakeholder?: {
                name?: string | null;
                logo?: string | null;
            } | null;
            name?: string | null;
            logo?: string | null;
        }> | null;
        issues?: Array<{
            id?: number | string;
            title?: string | null;
            description?: string | null;
            recommendation?: string | null;
            issue?: string | null;
            status?: string | null;
            createdAt?: string | null;
            issueStatus?: { name?: string | null; code?: string | null } | null;
            category?: { name?: string | null } | string | null;
            primaryAgency?: string | null;
            primaryAgencyLogo?: string | null;
            governmentAgencies?: Array<{
                stakeholder?: { name?: string | null; logo?: string | null } | null;
            }> | null;
        }> | null;
    } | null;
    guestEmails?: string[] | null;
    guestUserIds?: Array<string | number> | null;
    attendees?: Array<unknown> | null;
    guests?: Array<unknown> | null;
    issues?: Array<{
        id?: number | string;
        title?: string | null;
        issue?: string | null;
        description?: string | null;
        recommendation?: string | null;
        status?: string | null;
        createdAt?: string | null;
        issueStatus?: { name?: string | null; code?: string | null } | null;
        category?: { name?: string | null } | string | null;
        primaryAgency?: string | null;
        primaryAgencyLogo?: string | null;
        governmentAgencies?: Array<{
            stakeholder?: { name?: string | null; logo?: string | null } | null;
        }> | null;
    }> | null;
};

type ApiEnvelope<T> = {
    success?: boolean;
    message?: string;
    data?: T | { items?: T[]; meetings?: T[] };
    items?: T[];
};

const API_BASE_URL = (
    process.env.NEXT_PUBLIC_API_BASE_URL ??
    process.env.NEXT_PUBLIC_API_URL ??
    "http://localhost:3001/api/v1"
).replace(/\/+$/, "");

export const MEETING_CHANGED_EVENT = "gpsf-mis:meetings-changed";
export const MEETING_CHANGED_STORAGE_KEY = "gpsf-mis:meetings-changed";

function getAccessToken() {
    if (typeof window === "undefined") return null;

    return (
        window.localStorage.getItem("accessToken") ??
        window.localStorage.getItem("access_token") ??
        window.localStorage.getItem("token")
    );
}

function getHeaders(): HeadersInit {
    const token = getAccessToken();

    return {
        Accept: "application/json",
        ...(token ? { Authorization: `Bearer ${token}` } : {}),
    };
}

function asArray<T>(value: unknown): T[] {
    return Array.isArray(value) ? (value as T[]) : [];
}

function extractMeetings(payload: ApiEnvelope<ApiMeeting>): ApiMeeting[] {
    if (!payload) return [];
    if (Array.isArray(payload.items)) return payload.items;

    const data = payload.data;
    if (Array.isArray(data)) return data;

    if (data && typeof data === "object") {
        const dataObj = data as { items?: ApiMeeting[]; meetings?: ApiMeeting[] };
        if (Array.isArray(dataObj.items)) return dataObj.items;
        if (Array.isArray(dataObj.meetings)) return dataObj.meetings;
    }

    return [];
}

function dateKey(value?: string | null) {
    if (!value) return "";
    const match = value.match(/^\d{4}-\d{2}-\d{2}/);
    return match?.[0] ?? "";
}

function normalizeStatus(status?: string | null): MeetingCalendarStatus {
    const value = String(status ?? "").trim();
    const upper = value.toUpperCase();

    // Match ministry calendar status mapping so event cards use the same colors.
    if (upper === "DRAFT" || value === "Draft" || value === "Drafted") {
        return "Draft";
    }

    if (upper === "SCHEDULED" || value === "Scheduled") {
        return "Scheduled";
    }

    if (upper === "COMPLETED" || value === "Completed" || upper.includes("COMPLETE")) {
        return "Completed";
    }

    if (value.toLowerCase().includes("review")) {
        return "Under Review";
    }

    return "Submitted";
}

function eventColor(status: MeetingCalendarStatus): MeetingCalendarEventColor {
    if (status === "Completed") return "blue";
    if (status === "Submitted") return "green";
    if (status === "Under Review") return "orange";
    if (status === "Draft") return "orange";
    return "dark";
}

function mapIssues(meeting: ApiMeeting): MeetingCalendarIssue[] {
    const requestIssues = meeting.meetingRequest?.issues || [];
    const rawIssues = meeting.issues?.length ? meeting.issues : requestIssues;

    type RawIssueType = {
        id?: number | string;
        title?: string | null;
        issue?: string | null;
        description?: string | null;
        recommendation?: string | null;
        status?: string | null;
        createdAt?: string | null;
        issueStatus?: { name?: string | null; code?: string | null } | null;
        category?: { name?: string | null } | string | null;
        primaryAgency?: string | null;
        primaryAgencyLogo?: string | null;
        governmentAgencies?: Array<{
            stakeholder?: { name?: string | null; logo?: string | null } | null;
        }> | null;
    };

    return asArray<RawIssueType>(rawIssues).map((i) => {
        const firstIssueAgency = i.governmentAgencies?.[0]?.stakeholder;

        return {
            id: String(i.id || ""),
            title: String(i.title || i.issue || "Untitled Issue").replace(
                /<[^>]*>?/gm,
                "",
            ),
            description: String(i.description || "").replace(/<[^>]*>?/gm, ""),
            recommendation: String(i.recommendation || "").replace(/<[^>]*>?/gm, ""),
            category:
                (typeof i.category === "string"
                    ? i.category
                    : i.category?.name) || "—",
            status: i.issueStatus?.name || i.status || "Submitted",
            submittedDate: dateKey(i.createdAt) || "—",
            governmentAgency: i.primaryAgency || firstIssueAgency?.name || "—",
            governmentAgencyLogo:
                i.primaryAgencyLogo || firstIssueAgency?.logo || null,
        };
    });
}

function mapMeetingToCalendarEvent(
    meeting: ApiMeeting,
): MeetingCalendarEvent | null {
    const date = dateKey(meeting.meetingDate);
    if (!date) return null;

    const status = normalizeStatus(meeting.status);

    const participants =
        (meeting.guests?.length ?? 0) ||
        (meeting.guestEmails?.length ?? 0) +
        (meeting.guestUserIds?.length ?? 0) +
        (meeting.attendees?.length ?? 0);

    const firstAgency = meeting.meetingRequest?.governmentAgencies?.[0];
    const stakeholderName = firstAgency?.stakeholder?.name || firstAgency?.name;
    const stakeholderLogo = firstAgency?.stakeholder?.logo || firstAgency?.logo;

    const rawMeetingRequestId =
        meeting.meetingRequestId ?? meeting.meetingRequest?.id;
    const meetingRequestId = Number(rawMeetingRequestId);
    const hasMeetingRequestId =
        Number.isFinite(meetingRequestId) && meetingRequestId > 0;

    return {
        id: String(meeting.id),
        date,
        time: `${meeting.startTime || ""} - ${meeting.endTime || ""}`,
        startTime: meeting.startTime || "",
        endTime: meeting.endTime || "",
        title: meeting.title || "Untitled meeting",
        participants,
        color: eventColor(status),
        status,
        submittedDate: dateKey(meeting.createdAt ?? meeting.meetingDate) || "—",
        governmentAgency:
            stakeholderName ||
            meeting.user?.organization ||
            meeting.user?.name ||
            "Ministry",
        governmentAgencyLogo: stakeholderLogo || null,
        documentName: meeting.documentReference || "",
        documentSize: "",
        description: meeting.description || "",
        issues: mapIssues(meeting),
        meetingRequestId: hasMeetingRequestId ? meetingRequestId : null,
        meetingUpdate: {
            meetingDate: date,
            meetingTime: `${meeting.startTime || ""} - ${meeting.endTime || ""}`,
            startTime: meeting.startTime || "",
            endTime: meeting.endTime || "",
            referenceDocumentName: meeting.documentReference || "",
            referenceDocumentSize: "",
            progressSolutionTitle: "Meeting Details",
            progressSolutionDescription: meeting.description || "",
            solutionIndicatorsTitle: "Location",
            solutionIndicatorsDescription: meeting.location || "—",
        },
    };
}

export async function getMeetingCalendarEvents(
    signal?: AbortSignal,
): Promise<MeetingCalendarEvent[]> {
    const res = await fetch(`${API_BASE_URL}/meetings`, {
        method: "GET",
        headers: getHeaders(),
        credentials: "include",
        cache: "no-store",
        signal,
    });

    const payload: ApiEnvelope<ApiMeeting> = await res.json().catch(() => null);

    if (!res.ok) {
        throw new Error(payload?.message || "Unable to load meetings");
    }

    return extractMeetings(payload)
        .map(mapMeetingToCalendarEvent)
        .filter((event): event is MeetingCalendarEvent => event !== null)
        .sort((a, b) =>
            `${a.date} ${a.startTime}`.localeCompare(`${b.date} ${b.startTime}`),
        );
}

export function getChangedMeetingDate(value: string | null | undefined) {
    if (!value) return "";

    try {
        const parsed = JSON.parse(value);
        return dateKey(parsed?.meetingDate);
    } catch {
        return "";
    }
}
