import {
    toBackendStatus,
    toFrontendStatus,
    type CategoryOption,
    type DecisionIssueItem,
    type MinistryOption,
    type RgcDecisionRow,
    type RgcDecisionStatus,
    type RgcDecisionStatusCode,
} from "../rgc-decision-data";

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

type ApiMessage = string | string[] | undefined;

type ApiResponse<T> = {
    success?: boolean;
    statusCode?: number;
    message?: ApiMessage;
    data?: T;
};

type ApiListData<T> = {
    items?: T[];
    meta?: {
        total?: number;
        page?: number;
        limit?: number;
        totalPages?: number;
    };
};

type ApiNestedListData<T> = {
    data?: ApiListData<T> | T[];
    items?: T[];
};

type ApiListResponse<T> = ApiResponse<
    ApiListData<T> | T[] | ApiNestedListData<T>
> & {
    items?: T[];
    meta?: {
        total?: number;
        page?: number;
        limit?: number;
        totalPages?: number;
    };
};

type ApiAuthUser = {
    id?: number | string;
    userId?: number | string;
    sub?: number | string;
};

type ApiAuthMeResponse = {
    id?: number | string;
    userId?: number | string;
    sub?: number | string;

    user?: ApiAuthUser;

    data?: {
        id?: number | string;
        userId?: number | string;
        sub?: number | string;
        user?: ApiAuthUser;
    };

    message?: ApiMessage;
};

type JwtPayload = {
    id?: number | string;
    userId?: number | string;
    sub?: number | string;

    user?: {
        id?: number | string;
        userId?: number | string;
    };
};

type ApiStakeholder = {
    id: number;
    name?: string | null;
    shortName?: string | null;
    acronym?: string | null;
    logo?: string | null;
};

type ApiCategory = {
    id: number;
    name?: string | null;
};

export type IndicatorOption = {
    id: number;
    name: string;
    description?: string | null;
};

export type IssueOption = {
    id: number;
    title: string;
    description?: string | null;
};

type ApiIndicator = {
    id: number;
    name?: string | null;
    description?: string | null;
};

type ApiIssueStatus = {
    code?: string | null;
    name?: string | null;
};

type ApiIssue = {
    id?: number | string;
    title?: string | null;
    name?: string | null;
    description?: string | null;
    issueStatus?: ApiIssueStatus | null;
    status?: string | null;
};

type ApiUser = {
    id?: number;
    name?: string | null;
    email?: string | null;
};

export type PlenaryOption = {
    id: number;
    name: string;
};

type ApiPlenary = {
    id: number;
    name?: string | null;
    title?: string | null;
    description?: string | null;
};

type ApiRgcDecision = {
    id: number;

    plenaryId?: number | null;
    plenary?: ApiPlenary | null;
    plenaryName?: string | null;
    plenaryTitle?: string | null;

    stakeholderId?: number;
    stakeholder?: ApiStakeholder | null;
    ministry?: string | null;

    categoryId?: number;
    category?: string | ApiCategory | null;
    categoryInfo?: ApiCategory | null;

    indicatorId?: number | null;
    indicator?: ApiIndicator | string | null;
    indicatorName?: string | null;
    indicatorDescription?: string | null;

    meetingDate?: string | null;

    status?: string | null;
    statusCode?: string | null;

    focalPerson?: string | null;
    decision?: string | null;

    verificationSource?: string | null;
    sourceOfVerification?: string | null;
    verificationLink?: string | null;

    issues?: ApiIssue[];

    createdBy?: ApiUser | null;
    createdAt?: string | null;
    updatedAt?: string | null;
};

type RgcDecisionRowWithPlenary = RgcDecisionRow & {
    plenaryName?: string | null;
    plenaryTitle?: string | null;
};

export type CreateCdcRgcDecisionInput = {
    stakeholderId: number;
    ministry: string;

    plenaryId: number;
    plenary: string;

    categoryId: number;
    category: string;

    indicatorId: number;
    indicator: string;

    decision: string;
    meetingDate: string;
    status: RgcDecisionStatus;

    focalPerson: string;
    sourceOfVerification: string;
    verificationLink: string;

    issueIds?: number[];
    saveAsDraft?: boolean;
};

function toValidUserId(value: unknown): string {
    if (
        typeof value !== "string" &&
        typeof value !== "number"
    ) {
        return "";
    }

    const parsed = Number(value);

    if (
        !Number.isInteger(parsed) ||
        parsed < 1
    ) {
        return "";
    }

    return String(parsed);
}

function readStorageValue(
    key: string,
): string | null {
    if (typeof window === "undefined") {
        return null;
    }

    return (
        window.localStorage.getItem(key) ??
        window.sessionStorage.getItem(key)
    );
}

function getStoredToken(): string {
    if (typeof window === "undefined") {
        return "";
    }

    const tokenKeys = [
        "accessToken",
        "access_token",
        "token",
        "authToken",
        "auth_token",
        "jwt",
        "jwtToken",
        "bearerToken",
    ];

    for (const key of tokenKeys) {
        const token = readStorageValue(key)?.trim();

        if (token) {
            return token.replace(/^Bearer\s+/i, "");
        }
    }

    const objectKeys = [
        "auth",
        "session",
        "user",
        "authUser",
        "currentUser",
        "profile",
    ];

    for (const key of objectKeys) {
        const rawValue = readStorageValue(key);

        if (!rawValue) {
            continue;
        }

        try {
            const parsed = JSON.parse(rawValue) as {
                token?: string;
                accessToken?: string;
                access_token?: string;

                data?: {
                    token?: string;
                    accessToken?: string;
                    access_token?: string;
                };
            };

            const token =
                parsed.accessToken ??
                parsed.access_token ??
                parsed.token ??
                parsed.data?.accessToken ??
                parsed.data?.access_token ??
                parsed.data?.token;

            if (token?.trim()) {
                return token.trim().replace(/^Bearer\s+/i, "");
            }
        } catch {
            // Ignore invalid storage JSON.
        }
    }

    return "";
}

function decodeJwtPayload(
    token: string,
): JwtPayload | null {
    if (
        typeof window === "undefined" ||
        !token
    ) {
        return null;
    }

    const parts = token.split(".");

    if (parts.length < 2) {
        return null;
    }

    try {
        const base64 = parts[1]
            .replace(/-/g, "+")
            .replace(/_/g, "/");

        const padded = base64.padEnd(
            Math.ceil(base64.length / 4) * 4,
            "=",
        );

        const decoded = window.atob(padded);

        const json = decodeURIComponent(
            Array.from(decoded)
                .map(
                    (character) =>
                        `%${character
                            .charCodeAt(0)
                            .toString(16)
                            .padStart(2, "0")}`,
                )
                .join(""),
        );

        return JSON.parse(json) as JwtPayload;
    } catch {
        return null;
    }
}

function getUserIdFromJwt(): string {
    const token = getStoredToken();
    const payload = decodeJwtPayload(token);

    if (!payload) {
        return "";
    }

    return (
        toValidUserId(payload.id) ||
        toValidUserId(payload.userId) ||
        toValidUserId(payload.sub) ||
        toValidUserId(payload.user?.id) ||
        toValidUserId(payload.user?.userId)
    );
}

function getStoredUserId(): string {
    if (typeof window === "undefined") {
        return "";
    }

    const directKeys = [
        "userId",
        "user_id",
        "currentUserId",
        "authUserId",
        "auth_user_id",
        "current_user_id",
        "loginUserId",
    ];

    for (const key of directKeys) {
        const userId = toValidUserId(
            readStorageValue(key),
        );

        if (userId) {
            return userId;
        }
    }

    const objectKeys = [
        "user",
        "authUser",
        "currentUser",
        "auth",
        "profile",
        "session",
        "loginUser",
        "account",
    ];

    for (const key of objectKeys) {
        const rawValue = readStorageValue(key);

        if (!rawValue) {
            continue;
        }

        try {
            const parsed = JSON.parse(rawValue) as {
                id?: unknown;
                userId?: unknown;
                sub?: unknown;

                user?: {
                    id?: unknown;
                    userId?: unknown;
                    sub?: unknown;
                };

                data?: {
                    id?: unknown;
                    userId?: unknown;
                    sub?: unknown;

                    user?: {
                        id?: unknown;
                        userId?: unknown;
                        sub?: unknown;
                    };
                };
            };

            const userId =
                toValidUserId(parsed.id) ||
                toValidUserId(parsed.userId) ||
                toValidUserId(parsed.sub) ||
                toValidUserId(parsed.user?.id) ||
                toValidUserId(parsed.user?.userId) ||
                toValidUserId(parsed.user?.sub) ||
                toValidUserId(parsed.data?.id) ||
                toValidUserId(parsed.data?.userId) ||
                toValidUserId(parsed.data?.sub) ||
                toValidUserId(parsed.data?.user?.id) ||
                toValidUserId(parsed.data?.user?.userId) ||
                toValidUserId(parsed.data?.user?.sub);

            if (userId) {
                return userId;
            }
        } catch {
            // Ignore invalid storage JSON.
        }
    }

    return getUserIdFromJwt();
}

async function readJson<T>(
    response: Response,
): Promise<T> {
    const text = await response.text();

    if (!text) {
        return {} as T;
    }

    try {
        return JSON.parse(text) as T;
    } catch {
        throw new Error(
            "Backend returned an invalid JSON response.",
        );
    }
}

async function getUserIdFromAuthMe(): Promise<string> {
    const token = getStoredToken();

    try {
        const response = await fetch(
            `${API_BASE_URL}/auth/me`,
            {
                method: "GET",
                headers: {
                    Accept: "application/json",

                    ...(token
                        ? {
                            Authorization: `Bearer ${token}`,
                        }
                        : {}),
                },
                credentials: "include",
                cache: "no-store",
            },
        );

        if (!response.ok) {
            return "";
        }

        const result =
            await readJson<ApiAuthMeResponse>(
                response,
            );

        return (
            toValidUserId(result.data?.user?.id) ||
            toValidUserId(
                result.data?.user?.userId,
            ) ||
            toValidUserId(result.data?.user?.sub) ||
            toValidUserId(result.data?.id) ||
            toValidUserId(result.data?.userId) ||
            toValidUserId(result.data?.sub) ||
            toValidUserId(result.user?.id) ||
            toValidUserId(result.user?.userId) ||
            toValidUserId(result.user?.sub) ||
            toValidUserId(result.id) ||
            toValidUserId(result.userId) ||
            toValidUserId(result.sub)
        );
    } catch {
        return "";
    }
}

async function getCurrentUserId(): Promise<string> {
    const authUserId = await getUserIdFromAuthMe();

    if (authUserId) {
        return authUserId;
    }

    const storedUserId = getStoredUserId();

    if (storedUserId) {
        return storedUserId;
    }

    const environmentUserId = toValidUserId(
        process.env.NEXT_PUBLIC_CDC_GPSF_USER_ID,
    );

    if (environmentUserId) {
        return environmentUserId;
    }

    throw new Error(
        "Authenticated CDC G-PSF user ID was not found. Please login again.",
    );
}

async function getHeaders(
    includeContentType = false,
): Promise<HeadersInit> {
    const userId = await getCurrentUserId();
    const token = getStoredToken();

    return {
        Accept: "application/json",
        "x-user-id": userId,

        ...(includeContentType
            ? {
                "Content-Type": "application/json",
            }
            : {}),

        ...(token
            ? {
                Authorization: `Bearer ${token}`,
            }
            : {}),
    };
}

function getErrorMessage(
    message: ApiMessage,
    fallback = "Request failed.",
): string {
    if (Array.isArray(message)) {
        return message.join(", ");
    }

    if (
        typeof message === "string" &&
        message.trim()
    ) {
        return message;
    }

    return fallback;
}

function extractItems<T>(
    payload: unknown,
): T[] {
    if (!payload || typeof payload !== "object") return [];
    
    const record = payload as Record<string, unknown>;

    if (Array.isArray(payload)) return payload as T[];
    if (Array.isArray(record.items)) return record.items as T[];
    if (Array.isArray(record.data)) return record.data as T[];
    
    if (record.data && typeof record.data === "object") {
        const innerData = record.data as Record<string, unknown>;
        if (Array.isArray(innerData.items)) return innerData.items as T[];
        if (Array.isArray(innerData.data)) return innerData.data as T[];
    }

    return [];
}

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

    const text = String(value);

    if (/^\d{4}-\d{2}-\d{2}/.test(text)) {
        return text.slice(0, 10);
    }

    const date = new Date(value);

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

    return date.toISOString().slice(0, 10);
}

function getMinistryName(
    item: ApiRgcDecision,
): string {
    return (
        item.stakeholder?.shortName?.trim() ||
        item.stakeholder?.acronym?.trim() ||
        item.stakeholder?.name?.trim() ||
        item.ministry?.trim() ||
        "No data"
    );
}

function getCategoryName(
    item: ApiRgcDecision,
): string {
    if (
        typeof item.category === "string" &&
        item.category.trim()
    ) {
        return item.category.trim();
    }

    if (
        typeof item.category === "object" &&
        item.category?.name?.trim()
    ) {
        return item.category.name.trim();
    }

    return (
        item.categoryInfo?.name?.trim() ||
        "No data"
    );
}

function getPlenaryId(
    item: ApiRgcDecision,
): number | null {
    const value =
        item.plenaryId ??
        item.plenary?.id ??
        null;

    const parsed = Number(value);

    return Number.isInteger(parsed) && parsed > 0
        ? parsed
        : null;
}

function getPlenaryName(
    item: ApiRgcDecision,
): string {
    return (
        item.plenaryName?.trim() ||
        item.plenaryTitle?.trim() ||
        item.plenary?.name?.trim() ||
        item.plenary?.title?.trim() ||
        ""
    );
}

function getIndicatorName(
    item: ApiRgcDecision,
): string {
    if (
        typeof item.indicator === "string" &&
        item.indicator.trim()
    ) {
        return item.indicator.trim();
    }

    if (
        typeof item.indicator === "object" &&
        item.indicator?.name?.trim()
    ) {
        return item.indicator.name.trim();
    }

    if (item.indicatorName?.trim()) {
        return item.indicatorName.trim();
    }

    return "-";
}

function getStatusCode(
    item: ApiRgcDecision,
): RgcDecisionStatusCode {
    const normalized = String(
        item.statusCode ?? item.status ?? "",
    )
        .trim()
        .toUpperCase()
        .replace(/[\s-]+/g, "_");

    if (normalized === "SOLVED") {
        return "SOLVED";
    }

    if (normalized === "IN_PROGRESS") {
        return "IN_PROGRESS";
    }

    return "NOT_ADDRESSED";
}

function mapApiItem(
    item: ApiRgcDecision,
    index = 0,
    plenaryNameById?: ReadonlyMap<number, string>,
): RgcDecisionRowWithPlenary {
    const statusCode = getStatusCode(item);
    const plenaryId = getPlenaryId(item);

    const plenaryName =
        getPlenaryName(item) ||
        (plenaryId
            ? plenaryNameById?.get(plenaryId) ?? ""
            : "");

    const mappedIssues: DecisionIssueItem[] = Array.isArray(item.issues)
        ? item.issues.map((issue) => ({
              id: Number(issue.id) || 0,
              title:
                  issue.title?.trim() ||
                  issue.name?.trim() ||
                  `Issue ${issue.id ?? 1}`,
              description:
                  issue.description?.trim() || null,
          }))
        : [];

    return {
        id: Number(item.id) || index + 1,

        plenaryId,
        plenaryName: plenaryName || null,
        plenaryTitle: plenaryName || null,

        stakeholderId: Number(
            item.stakeholderId ??
            item.stakeholder?.id ??
            0,
        ),

        ministry: getMinistryName(item),
        ministryLogo:
            item.stakeholder?.logo ?? null,

        categoryId: Number(
            item.categoryId ??
            item.categoryInfo?.id ??
            (typeof item.category === "object"
                ? item.category?.id
                : 0) ??
            0,
        ),

        category: getCategoryName(item),

        decision:
            item.decision?.trim() || "No data",

        meetingDate:
            formatDate(item.meetingDate),

        status:
            toFrontendStatus(statusCode),

        statusCode,

        indicator: getIndicatorName(item),

        focalPerson:
            item.focalPerson?.trim() ||
            "No data",

        sourceOfVerification:
            item.sourceOfVerification?.trim() ||
            item.verificationSource?.trim() ||
            "No data",

        verificationLink:
            item.verificationLink?.trim() ||
            "",

        issues: mappedIssues,

        createdAt:
            item.createdAt ?? undefined,

        updatedAt:
            item.updatedAt ?? undefined,
    };
}

export async function getCdcRgcDecisions(): Promise<
    RgcDecisionRow[]
> {
    const params = new URLSearchParams({
        page: "1",
        limit: "100",
    });

    const headers = await getHeaders();

    const response = await fetch(
        `${API_BASE_URL}/rgc-decisions/cdc-gpsf?${params.toString()}`,
        {
            method: "GET",
            headers,
            credentials: "include",
            cache: "no-store",
        },
    );

    const payload =
        await readJson<
            ApiListResponse<ApiRgcDecision>
        >(response);

    if (!response.ok) {
        throw new Error(
            getErrorMessage(
                payload.message,
                "Unable to load CDC G-PSF RGC Decisions.",
            ),
        );
    }

    const items = extractItems<ApiRgcDecision>(payload);

    const needsPlenaryLookup = items.some(
        (item) =>
            Boolean(getPlenaryId(item)) &&
            !getPlenaryName(item),
    );

    let plenaryNameById = new Map<number, string>();

    if (needsPlenaryLookup) {
        const plenaries = await fetchPlenaryOptions(headers);

        plenaryNameById = new Map(
            plenaries
                .map((plenary) => {
                    const id = Number(plenary.id);
                    const name =
                        plenary.name?.trim() ||
                        plenary.title?.trim() ||
                        "";

                    return [id, name] as const;
                })
                .filter(
                    ([id, name]) =>
                        Number.isInteger(id) &&
                        id > 0 &&
                        Boolean(name),
                ),
        );
    }

    return items.map((item, index) =>
        mapApiItem(
            item,
            index,
            plenaryNameById,
        ),
    );
}

async function fetchIndicatorOptions(
    headers: HeadersInit,
): Promise<ApiIndicator[]> {
    const endpoints = [
        `${API_BASE_URL}/indicators/options`,
        `${API_BASE_URL}/indicators?limit=100`,
        `${API_BASE_URL}/indicators`,
        `${API_BASE_URL}/rgc-decisions/lookups/indicators`,
    ];

    for (const endpoint of endpoints) {
        try {
            const response = await fetch(endpoint, {
                method: "GET",
                headers,
                credentials: "include",
                cache: "no-store",
            });
            const payload = await readJson<ApiListResponse<ApiIndicator>>(response);
            if (response.ok) {
                const items = extractItems<ApiIndicator>(payload);
                if (items.length > 0) return items;
            }
        } catch {
            // Continue
        }
    }

    return [];
}

async function fetchPlenaryOptions(
    headers: HeadersInit,
): Promise<ApiPlenary[]> {
    const endpoints = [
        `${API_BASE_URL}/rgc-decisions/lookups/plenaries`,
        `${API_BASE_URL}/plenaries/options`,
        `${API_BASE_URL}/plenaries?limit=100`,
        `${API_BASE_URL}/plenaries`,
    ];

    for (const endpoint of endpoints) {
        try {
            const response = await fetch(endpoint, {
                method: "GET",
                headers,
                credentials: "include",
                cache: "no-store",
            });
            const payload = await readJson<ApiListResponse<ApiPlenary>>(response);
            if (response.ok) {
                const items = extractItems<ApiPlenary>(payload);
                if (items.length > 0) return items;
            }
        } catch {
            // Continue
        }
    }

    return [];
}

export async function getRgcDecisionIssues(): Promise<IssueOption[]> {
    const headers = await getHeaders();
    try {
        const response = await fetch(`${API_BASE_URL}/rgc-decisions/lookups/issues`, {
            method: "GET",
            headers,
            credentials: "include",
            cache: "no-store",
        });

        const payload = await readJson<ApiListResponse<ApiIssue>>(response);

        if (!response.ok) {
            return [];
        }

        const items = extractItems<ApiIssue>(payload);

        return items
            .filter((item) => {
                const status = String(
                    item.issueStatus?.code ?? 
                    item.issueStatus?.name ?? 
                    item.status ?? 
                    ""
                ).trim().toUpperCase().replace(/[\s-]+/g, "_");

                if (!status) return true;
                return status.includes("IN_PROGRESS") || status.includes("NOT_ADDRESSED");
            })
            .map((item) => ({
                id: Number(item.id) || 0,
                title: item.title?.trim() || item.name?.trim() || `Issue ${item.id ?? 1}`,
                description: item.description?.trim() || null,
            }))
            .filter((item) => Number.isInteger(item.id) && item.id > 0);
    } catch {
        return [];
    }
}

export async function getCdcRgcDecisionLookups(): Promise<{
    ministries: MinistryOption[];
    plenaries: PlenaryOption[];
    categories: CategoryOption[];
    indicators: IndicatorOption[];
    issues: IssueOption[]; 
}> {
    const headers = await getHeaders();

    const [
        ministriesResponse,
        plenariesList,
        categoriesResponse,
        indicatorsList,
        issuesList,
    ] = await Promise.all([
        fetch(
            `${API_BASE_URL}/rgc-decisions/lookups/ministries`,
            {
                method: "GET",
                headers,
                credentials: "include",
                cache: "no-store",
            },
        ),
        fetchPlenaryOptions(headers),
        fetch(
            `${API_BASE_URL}/rgc-decisions/lookups/categories`,
            {
                method: "GET",
                headers,
                credentials: "include",
                cache: "no-store",
            },
        ),
        fetchIndicatorOptions(headers),
        getRgcDecisionIssues(), 
    ]);

    const ministriesPayload = await readJson<ApiListResponse<ApiStakeholder>>(ministriesResponse);
    const categoriesPayload = await readJson<ApiListResponse<ApiCategory>>(categoriesResponse);

    const ministries = extractItems<ApiStakeholder>(
        ministriesPayload,
    )
        .map((item) => ({
            id: Number(item.id),
            name:
                item.shortName?.trim() ||
                item.acronym?.trim() ||
                item.name?.trim() ||
                `Ministry ${item.id}`,
            logo: item.logo ?? null,
        }))
        .filter(
            (item) =>
                Number.isInteger(item.id) &&
                item.id > 0,
        );

    const plenaries = plenariesList
        .map((item) => ({
            id: Number(item.id),
            name:
                item.name?.trim() ||
                item.title?.trim() ||
                `Plenary ${item.id}`,
        }))
        .filter(
            (item) =>
                Number.isInteger(item.id) &&
                item.id > 0,
        );

    const categories = extractItems<ApiCategory>(
        categoriesPayload,
    )
        .map((item) => ({
            id: Number(item.id),
            name:
                item.name?.trim() ||
                `Category ${item.id}`,
        }))
        .filter(
            (item) =>
                Number.isInteger(item.id) &&
                item.id > 0,
        );

    const indicators = indicatorsList
        .map((item) => ({
            id: Number(item.id),
            name:
                item.name?.trim() ||
                `Indicator ${item.id}`,
            description:
                item.description?.trim() || null,
        }))
        .filter(
            (item) =>
                Number.isInteger(item.id) &&
                item.id > 0 &&
                Boolean(item.name),
        );

    return {
        ministries,
        plenaries,
        categories,
        indicators,
        issues: issuesList, 
    };
}

export async function createCdcRgcDecision(
    input: CreateCdcRgcDecisionInput,
): Promise<RgcDecisionRow> {
    if (
        !Number.isInteger(input.stakeholderId) ||
        input.stakeholderId < 1
    ) {
        throw new Error(
            "Please select a Ministry.",
        );
    }

    if (
        !Number.isInteger(input.plenaryId) ||
        input.plenaryId < 1
    ) {
        throw new Error(
            "Please select a Plenary.",
        );
    }

    if (
        !Number.isInteger(input.categoryId) ||
        input.categoryId < 1
    ) {
        throw new Error(
            "Please select a Category.",
        );
    }

    if (
        !Number.isInteger(input.indicatorId) ||
        input.indicatorId < 1
    ) {
        throw new Error(
            "Please select an Indicator.",
        );
    }

    if (!input.meetingDate.trim()) {
        throw new Error(
            "Meeting Date is required.",
        );
    }

    if (!input.focalPerson.trim()) {
        throw new Error(
            "Focal Person is required.",
        );
    }

    if (!input.decision.trim()) {
        throw new Error(
            "RGC Decision is required.",
        );
    }

    if (
        !input.sourceOfVerification.trim()
    ) {
        throw new Error(
            "Source of Verification is required.",
        );
    }

    const response = await fetch(
        `${API_BASE_URL}/rgc-decisions/cdc-gpsf`,
        {
            method: "POST",
            headers: await getHeaders(true),
            credentials: "include",
            cache: "no-store",

            body: JSON.stringify({
                stakeholderId:
                    input.stakeholderId,

                plenaryId:
                    input.plenaryId,

                categoryId:
                    input.categoryId,

                indicatorId:
                    input.indicatorId,

                meetingDate:
                    input.meetingDate,

                status:
                    toBackendStatus(input.status),

                focalPerson:
                    input.focalPerson.trim(),

                decision:
                    input.decision.trim(),

                verificationSource:
                    input.sourceOfVerification.trim(),

                verificationLink:
                    input.verificationLink.trim(),

                issueIds: input.issueIds ?? [], 
                saveAsDraft:
                    input.saveAsDraft ?? false,
            }),
        },
    );

    const payload =
        await readJson<
            ApiResponse<ApiRgcDecision>
        >(response);

    if (!response.ok) {
        throw new Error(
            getErrorMessage(
                payload.message,
                input.saveAsDraft
                    ? "Unable to save RGC Decision draft."
                    : "Unable to create RGC Decision.",
            ),
        );
    }

    const item = payload.data;

    if (!item?.id) {
        throw new Error(
            "Created RGC Decision was not returned from backend.",
        );
    }

    return mapApiItem({
        ...item,
        plenaryId:
            item.plenaryId ??
            input.plenaryId,
        plenary:
            item.plenary ??
            {
                id: input.plenaryId,
                name: input.plenary,
            },
        plenaryName:
            item.plenaryName ??
            input.plenary,
    });
}