import "server-only";
import type { Lang } from "@/config/constants";
import { apiBase, apiGet, apiGetWithStatus } from "./api";
import { coursePath, encodePath, parseCourseParam } from "@/lib/course-url";
import { firstText, toIsoDate } from "./text";

/**
 * سجل الكيانات الديناميكية. كل كيان يصف:
 *  - endpoint: نفس الطلب الذي يرسله المكوّن الأصلي في المتصفح
 *  - queryKey: نفس مفتاح React Query في المكوّن الأصلي حرفياً — شرط أساسي
 *    كي يجد المكوّن البيانات جاهزة عند أول تصيير (Hydration) فيظهر المحتوى
 *    كاملاً في HTML الذي يقرؤه محرك البحث
 *  - select: نفس تحويل الاستجابة الذي يجريه queryFn الأصلي
 *  - section / listPath: لعنوان الصفحة ومسار التنقل
 */
export type EntityKind =
    | "course"
    | "blog"
    | "news"
    | "podcast"
    | "seminar"
    | "offer"
    | "achievement"
    | "accreditation"
    | "trainingPlan";

type EntityDef = {
    endpoint: (id: string) => string;
    queryKey: (id: string, URL: string) => unknown[];
    select: (json: any) => any;
    /** للوصول إلى الكائن الفعلي داخل ما يعيده select (العروض تعيد الاستجابة كاملة) */
    record?: (selected: any) => any;
    /** مفتاح ترجمة القسم + المسار المرجعي — من PageTitles الأصلي */
    sectionKey: string;
    fallbackTitleKey: string;
    listPath: string;
    /** هل يُلحق اسم القسم بالعنوان: "العنوان | القسم" */
    titleWithSection: boolean;
    /** يستخرج المعرّف من جزء الرابط (مثل "12-عنوان" → "12")؛ null = رابط غير صالح */
    parseId?: (param: string) => string | null;
    /** المسار القانوني للكيان (غير مرمَّز)؛ الافتراضي listPath/id */
    canonicalPath?: (id: string, record: any) => string;
};

export const ENTITIES: Record<EntityKind, EntityDef> = {
    course: {
        endpoint: (id) => `/courses/${id}`,
        queryKey: (id, URL) => ["course-details", id, URL],
        select: (j) => j?.data,
        sectionKey: "routes.training-courses",
        fallbackTitleKey: "routes.training-courses-details",
        listPath: "/training-courses",
        titleWithSection: true,
        // /training-courses/{id}-{slug}: الرقم وحده يُستخدم مع الـ API
        parseId: (param) => parseCourseParam(param),
        canonicalPath: (id, record) => coursePath(id, record?.title),
    },
    blog: {
        endpoint: (id) => `/blogs/${id}`,
        queryKey: (id, URL) => ["blog-details", id, URL],
        select: (j) => j?.data || {},
        sectionKey: "routes.all-blogs",
        fallbackTitleKey: "routes.blog-details",
        listPath: "/blogs",
        titleWithSection: true,
    },
    news: {
        endpoint: (id) => `/latestNews/${id}`,
        queryKey: (id, URL) => ["newsDetails", id, URL],
        select: (j) => j?.data,
        sectionKey: "routes.news",
        fallbackTitleKey: "routes.news-details",
        listPath: "/news",
        titleWithSection: true,
    },
    podcast: {
        endpoint: (id) => `/podcasts/${id}`,
        queryKey: (id, URL) => ["podcast-details", id, URL],
        select: (j) => j?.data ?? j?.data?.data,
        sectionKey: "routes.podcasts",
        fallbackTitleKey: "routes.podcast-details",
        listPath: "/podcasts",
        titleWithSection: true,
    },
    seminar: {
        endpoint: (id) => `/seminars/${id}`,
        queryKey: (id, URL) => ["seminar-details", id, URL],
        select: (j) => j?.data?.data ?? j?.data,
        sectionKey: "routes.seminars",
        fallbackTitleKey: "routes.seminar-details",
        listPath: "/seminars",
        titleWithSection: true,
    },
    offer: {
        endpoint: (id) => `/offers/${id}`,
        queryKey: (id, URL) => ["offers-details", id, URL],
        select: (j) => j,
        record: (s) => s?.data,
        sectionKey: "routes.offers",
        fallbackTitleKey: "routes.offer-details",
        listPath: "/offers",
        titleWithSection: true,
    },
    achievement: {
        endpoint: (id) => `/home-pages/${id}`,
        // المكوّن الأصلي لا يضمّن URL في المفتاح — نحافظ على ذلك حرفياً
        queryKey: (id) => ["achievement-details", id],
        select: (j) => j?.data,
        sectionKey: "routes.achievements",
        fallbackTitleKey: "routes.achievement-details",
        listPath: "/achievements",
        titleWithSection: false,
    },
    accreditation: {
        endpoint: (id) => `/dependencies/${id}`,
        queryKey: (id, URL) => ["dependency-details", id, URL],
        select: (j) => j?.data,
        sectionKey: "routes.accreditations",
        fallbackTitleKey: "routes.dependency-details",
        listPath: "/accreditations",
        titleWithSection: true,
    },
    trainingPlan: {
        endpoint: (id) => `/categories/${id}`,
        queryKey: (id, URL) => ["category-data", id, URL],
        select: (j) => j?.data,
        sectionKey: "routes.training-plan",
        fallbackTitleKey: "routes.training-plan-single",
        listPath: "/training-plans",
        titleWithSection: true,
    },
};

export type LoadedEntity = {
    kind: EntityKind;
    id: string;
    lang: Lang;
    /** ما يعيده queryFn الأصلي — يُحقن في React Query */
    selected: any;
    /** الكائن نفسه (عنوان، صورة، ...) */
    record: any;
    queryKey: unknown[];
    title: string;
    description: string;
    image?: string;
    published?: string;
    modified?: string;
    /** كلمات مفتاحية من بيانات الكيان نفسه (التصنيف، المجال، اللغة) */
    keywords: string[];
};

const titles = (v: any): string[] => (Array.isArray(v) ? v.map((x) => x?.title ?? x?.name).filter(Boolean) : []);

/** كلمات مفتاحية حقيقية من الكيان — بلا تكرار وبلا القيم الفارغة "-" */
function entityKeywords(r: any): string[] {
    const raw = [
        r?.subject?.category?.title,
        r?.category?.title,
        r?.category?.name,
        r?.subject?.title,
        r?.program_type?.title,
        ...titles(r?.courselanguage),
        ...titles(r?.dependences),
        ...titles(r?.tags),
    ];
    return [...new Set(raw.filter((v) => typeof v === "string" && v.trim() && v.trim() !== "-").map((v) => v.trim()))].slice(0, 12);
}

/**
 * يُستدعى مرتين لكل صفحة (generateMetadata ثم الصفحة نفسها) — fetch في Next
 * يزيل التكرار تلقائياً داخل الطلب الواحد، فلا يُرسل للـ API إلا طلب واحد.
 */
/**
 * يعاد عندما يؤكد الـ API (404) أن الكيان غير موجود (محذوف أو رابط خاطئ).
 * لا نستخدم notFound() هنا: في Next 15.5 يصل جسم الصفحة فارغاً من الخادم
 * (<html id="__next_error__">) ولا تظهر صفحة 404 إلا بعد تحميل JavaScript.
 * بدلاً من ذلك تعرض entity-route صفحة 404 كاملة فوراً مع noindex.
 */
export const ENTITY_MISSING = Symbol("entity-missing");

export async function loadEntity(kind: EntityKind, id: string, lang: Lang): Promise<LoadedEntity | null | typeof ENTITY_MISSING> {
    const def = ENTITIES[kind];
    const res = await apiGetWithStatus(lang, def.endpoint(id));
    if (res.notFound) return ENTITY_MISSING;
    const json = res.data;
    if (!json) return null;
    const selected = def.select(json);
    const record = def.record ? def.record(selected) : selected;
    if (!record || (typeof record === "object" && Object.keys(record).length === 0)) return null;

    return {
        kind,
        id,
        lang,
        selected,
        record,
        queryKey: def.queryKey(id, apiBase(lang)),
        title: firstText(record, ["title", "name", "category.name"]),
        description: firstText(record, [
            "meta_description",
            "summary",
            "description",
            "short_description",
            "blog",
            "content",
            "details.0.description",
            "category.description",
            "course",
        ]),
        image: firstText(record, ["image", "image_cover", "cover", "thumbnail", "category.image"]) || undefined,
        published: toIsoDate(record?.date || record?.created_at || record?.start_date),
        modified: toIsoDate(record?.updated_at),
        keywords: entityKeywords(record),
    };
}

/** المعرّف من جزء الرابط حسب نوع الكيان (null = رابط غير صالح → صفحة 404) */
export function resolveEntityId(kind: EntityKind, param: string): string | null {
    const def = ENTITIES[kind];
    return def.parseId ? def.parseId(param) : param;
}

/** المسار القانوني مرمَّزاً (ASCII) — للروابط القانونية وhreflang وJSON-LD */
export function entityCanonicalPath(kind: EntityKind, id: string, record?: any): string {
    const def = ENTITIES[kind];
    return encodePath(def.canonicalPath ? def.canonicalPath(id, record) : `${def.listPath}/${id}`);
}

/**
 * مدن انعقاد البرنامج: نفس طلب ومفتاح React Query في online-offline.tsx
 * (['cities-of-course', id, URL] ← /cities?course_id={id} مرتبة حسب sort)
 */
export async function loadCourseCities(id: string, lang: Lang) {
    const json = await apiGet<any>(lang, `/cities?course_id=${id}`);
    const list = json?.data?.data;
    return {
        queryKey: ["cities-of-course", id, apiBase(lang)] as unknown[],
        data: Array.isArray(list) ? [...list].sort((a: any, b: any) => a?.sort - b?.sort) : undefined,
    };
}

/**
 * مواعيد انعقاد البرنامج: نفس الطلب ومفتاح React Query في صفحة التفاصيل
 * (['city-distributions', id, URL] ← /courses/{id}?city_id=6)
 */
export async function loadCourseDistributions(id: string, lang: Lang) {
    const json = await apiGet<any>(lang, `/courses/${id}?city_id=6`);
    const data = json?.data ?? null;
    return {
        queryKey: ["city-distributions", id, apiBase(lang)] as unknown[],
        data,
        distribution: Array.isArray(data?.distribution) ? (data.distribution as any[]) : [],
    };
}
