import TaleButton from "@components/TaleButton";
import { Button } from "@mui/material";
import React, { Suspense, useMemo, useState } from "react";
import { SingleQuestion } from "@pages/survey/surveyId/questions/SingleQuestion";
import { TaleDashbaordMainCard } from "@components/TaleDashbaordMainCard";
import { useNavigate, useParams } from "react-router-dom";
import { TaleLoadingFallback } from "@components/TaleLoadingFallback";
import { lazily } from "react-lazily";
import { useQuery } from "@tanstack/react-query";
import { ErrorBoundary } from "react-error-boundary";
import { surveysService } from "@/api/surveys";
import { formatQuestionApiToUi } from "@/utils/questionFormatApiToUi";
import { ErrorWrapper } from "@/components/ErrorWrapper";
import { useTranslation } from "@/hooks/useTranslation";
import { registerArabicFont, ARABIC_FONT_FAMILY } from "@/utils/pdf/arabicFont";
import { shapeArabicText } from "@/utils/pdf/arabicShaping";
import { reorderForDisplay } from "@/utils/pdf/arabicBidi";
import enMessages from "@/locales/en.json";
import frMessages from "@/locales/fr.json";
import arMessages from "@/locales/ar.json";
import {
    FiClock,
    FiStar,
    FiChevronRight,
    FiChevronLeft,
    FiDownload,
    FiEye,
} from "react-icons/fi";

const { NotFound } = lazily(() => import("@components/Errors/NotFound"));

// Arabic (0600-06FF), Arabic Supplement (0750-077F), Arabic Extended-A
// (08A0-08FF), Arabic Presentation Forms-A (FB50-FDFF), and Arabic
// Presentation Forms-B (FE70-FEFF) Unicode blocks. Built from numeric code
// points rather than a literal character range so the source file never
// contains the actual (partly invisible/combining) Arabic characters —
// one of them, U+FEFF, is a zero-width mark ESLint's no-irregular-whitespace
// rule rejects outright when it appears as source text.
//
// Detecting RTL export layout from the survey's own `language` field is
// unreliable — plenty of surveys carry Arabic content with an unset or
// mismatched language field — so instead we scan the actual text that will
// be printed for Arabic script and let that decide.
const ARABIC_UNICODE_BLOCKS = [
    [0x0600, 0x06ff],
    [0x0750, 0x077f],
    [0x08a0, 0x08ff],
    [0xfb50, 0xfdff],
    [0xfe70, 0xfeff],
];
const ARABIC_SCRIPT_REGEX = new RegExp(
    "[" +
        ARABIC_UNICODE_BLOCKS.map(
            ([start, end]) => String.fromCodePoint(start) + "-" + String.fromCodePoint(end)
        ).join("") +
        "]"
);

const containsArabicScript = (survey, questions) => {
    const optionLabel = (opt) => (typeof opt === "string" ? opt : opt?.text);
    const texts = [
        survey?.title,
        survey?.description,
        ...(questions || []).flatMap((q) => [
            q.text,
            q.description,
            ...(q.options || q.possibleResponses || []).map(optionLabel),
        ]),
    ];
    return texts.some((text) => typeof text === "string" && ARABIC_SCRIPT_REGEX.test(text));
};

// PDF-only, non-hook counterpart to useTranslation: the strings baked into the
// exported PDF (e.g. the format-hint line) must follow the SURVEY's own
// authored language, not the dashboard viewer's UI language, so they can't go
// through the `t()` from useTranslation() (which reads the Redux UI-language
// slice). useTranslation can't be called here either way — this runs inside
// an async click handler, not component render, so calling a hook would break
// the rules of hooks. This mirrors useTranslation's dot-key lookup against
// the same locale JSON files.
const PDF_LOCALE_MESSAGES = { en: enMessages, fr: frMessages, ar: arMessages };
const SURVEY_LANGUAGE_TO_LOCALE = { ENGLISH: "en", FRENCH: "fr", ARABIC: "ar" };

const resolvePdfLocale = (isRtl, surveyLanguage) => {
    // isRtl comes from containsArabicScript, i.e. a scan of the survey's actual
    // text — it's the trustworthy signal (see the note above on why the
    // `language` field alone is unreliable for Arabic detection), so it wins
    // whenever it says the content is Arabic. Otherwise fall back to the
    // survey's declared language for choosing between en/fr.
    if (isRtl) return "ar";
    const normalized = (surveyLanguage || "").trim().toUpperCase();
    return SURVEY_LANGUAGE_TO_LOCALE[normalized] === "ar"
        ? "en" // declared Arabic but no Arabic script detected: trust isRtl, not the field
        : SURVEY_LANGUAGE_TO_LOCALE[normalized] ?? "en";
};

const tForPdf = (locale, key) => {
    const messages = PDF_LOCALE_MESSAGES[locale] ?? PDF_LOCALE_MESSAGES.en;
    const value = key.split(".").reduce((obj, k) => obj?.[k], messages);
    return typeof value === "string" ? value : null;
};

const SurveyPreview = () => {
    const { t } = useTranslation();
    const nav = useNavigate();
    const { surveyId } = useParams();

    const [currentStep, setCurrentStep] = useState(0);
    const [exporting, setExporting] = useState(false);

    const { isPending: loading, data, error } = useQuery({
        queryKey: ["survey-preview", surveyId],
        queryFn: async () => {
            const { questions: rawQuestions, company, assets, ...survey } =
                await surveysService.getSurvey(surveyId);

            const questions = rawQuestions.filter((q) => q.text && q.questionType);

            return { company, questions, survey, assets };
        },
        retry: false,
    });

    const steps = useMemo(() => (loading || !data ? 0 : data.questions.length), [data, loading]);

    const formattedQuestion = useMemo(() => {
        if (!data?.questions?.length) return {};
        return formatQuestionApiToUi(data.questions[currentStep] || data.questions[0]);
    }, [data, currentStep]);

    const progressPercentage = useMemo(() => {
        if (steps === 0) return 0;
        return ((currentStep + 1) / steps) * 100;
    }, [currentStep, steps]);

    // Local, throwaway answer state — nothing is persisted, this only lets
    // SingleQuestion render its selection UI without crashing.
    const [previewAnswer, setPreviewAnswer] = useState({});

    const handleNext = () => {
        if (currentStep < steps - 1) setCurrentStep((prev) => prev + 1);
    };

    const handlePrevious = () => {
        if (currentStep > 0) setCurrentStep((prev) => prev - 1);
    };

    const handleExportPdf = async () => {
        if (!data?.questions?.length) return;
        setExporting(true);
        try {
            const isRtl = containsArabicScript(data.survey, data.questions);
            const pdfLocale = resolvePdfLocale(isRtl, data.survey?.language);

            const { jsPDF } = await import("jspdf");

            // jsPDF ships its own built-in Arabic shaping (__arabicParser__). It
            // hooks in at two points: (1) a "preProcessText" event fired on every
            // doc.text() call, and (2) a direct call from
            // getStringUnitWidth/splitTextToSize, which checks
            // `if (API.processArabic)` and runs it during text-width measurement
            // regardless of the event subscription. Both duplicate and conflict
            // with our own shaping/bidi pipeline below: they re-parse text we've
            // already shaped into presentation-form glyphs, misidentify them as
            // base letters, and reshape/reorder a second time — corrupting both
            // the rendered glyphs and the width measurements splitTextToSize
            // relies on for word-wrapping. Deleting the function removes both
            // call sites at once; the events filter is kept as a belt-and-braces
            // guard. Must run before `new jsPDF(...)`.
            delete jsPDF.API.processArabic;
            jsPDF.API.events = (jsPDF.API.events || []).filter(
                ([name]) => name !== "preProcessText"
            );

            const doc = new jsPDF({ unit: "pt", format: "a4" });
            if (isRtl) await registerArabicFont(doc);
            const pageWidth = doc.internal.pageSize.getWidth();
            const pageHeight = doc.internal.pageSize.getHeight();
            const margin = 60;
            const maxWidth = pageWidth - margin * 2;
            const accent = [0, 173, 155];
            const dark = [26, 26, 26];
            const gray = [140, 140, 140];
            const lightGray = [225, 225, 225];
            let y = margin;
            let pageNum = 1;

            // RTL layout anchors: `edgeX` is the outer margin on the side text
            // starts from (right margin for Arabic, left for everything else);
            // `contentX` is indented 30pt toward the center from there, used
            // for question text/options that sit "after" the question number.
            const align = isRtl ? "right" : undefined;
            const edgeX = isRtl ? pageWidth - margin : margin;
            const contentX = isRtl ? pageWidth - margin - 30 : margin + 30;
            const contentWidth = maxWidth - 30;

            // jsPDF has no Arabic shaping/bidi of its own (now that its built-in
            // parser is stripped above) — every string that may contain Arabic
            // content is routed through this before being handed to doc.text().
            // Shaping (joining letters into their contextual forms) must happen
            // on the full logical text before word-wrapping, since
            // splitTextToSize needs to measure the actual glyphs that will be
            // drawn; bidi reordering (into left-to-right visual order for
            // jsPDF's renderer) only makes sense per wrapped line, so it's
            // applied after splitTextToSize, one line at a time.
            const wrapText = (text, width) => {
                const shaped = isRtl ? shapeArabicText(text || "") : (text || "");
                const lines = doc.splitTextToSize(shaped, width);
                return isRtl ? lines.map((line) => reorderForDisplay(line)) : lines;
            };

            const setDocFont = (style = "normal") => {
                if (isRtl) {
                    // Tajawal has no italic cut; Arabic script has no italic
                    // form anyway, so normal weight is the correct fallback.
                    doc.setFont(ARABIC_FONT_FAMILY, style === "italic" ? "normal" : style);
                } else {
                    doc.setFont("helvetica", style);
                }
            };

            const drawFooter = () => {
                setDocFont("normal");
                doc.setFontSize(8.5);
                doc.setTextColor(...gray);
                doc.text(String(pageNum), pageWidth / 2, pageHeight - 32, { align: "center" });
                doc.setTextColor(...dark);
            };

            const addPage = () => {
                drawFooter();
                doc.addPage();
                pageNum += 1;
                y = margin;
            };

            const ensureSpace = (needed) => {
                if (y + needed > pageHeight - margin - 20) addPage();
            };

            // ---- Title block ----
            setDocFont("bold");
            doc.setFontSize(21);
            doc.setTextColor(...dark);
            const titleLines = wrapText(data.survey?.title || "Survey", maxWidth);
            doc.text(titleLines, edgeX, y, { align });
            y += titleLines.length * 25;

            if (data.survey?.description) {
                setDocFont("normal");
                doc.setFontSize(10.5);
                doc.setTextColor(...gray);
                const descLines = wrapText(data.survey.description, maxWidth);
                doc.text(descLines, edgeX, y + 6, { align });
                y += descLines.length * 14 + 12;
            }

            y += 30;

            // ---- Questions ----
            data.questions.forEach((q, index) => {
                const numLabel = String(index + 1).padStart(2, "0");
                // Human-readable description of what the response format looks like
                // (e.g. "Rating from 1 to 5 stars") rather than the raw enum value —
                // resolved in the SURVEY's own language (pdfLocale), not the
                // dashboard viewer's UI language, and falls back to the old
                // raw-label behavior for any type with no hint.
                const hintKey = `surveyBuilder.preview.pdfFormatHints.${q.questionType}`;
                const hint = tForPdf(pdfLocale, hintKey);
                const typeLabel =
                    hint ?? (q.questionType || "").replace(/_/g, " ").toLowerCase();

                ensureSpace(56);

                // number, small and colored, sits at the leading edge of the question
                setDocFont("bold");
                doc.setFontSize(10);
                doc.setTextColor(...accent);
                doc.text(isRtl ? [numLabel] : numLabel, edgeX, y, { align });
                doc.setTextColor(...dark);

                setDocFont("bold");
                doc.setFontSize(13);
                const qLines = wrapText(q.text || "", contentWidth);
                doc.text(qLines, contentX, y, { align });
                y += qLines.length * 17;

                if (q.description) {
                    setDocFont("normal");
                    doc.setFontSize(9.5);
                    doc.setTextColor(...gray);
                    const descLines = wrapText(q.description, contentWidth);
                    ensureSpace(descLines.length * 12 + 6);
                    doc.text(descLines, contentX, y + 4, { align });
                    y += descLines.length * 12 + 8;
                }

                setDocFont("italic");
                doc.setFontSize(8.5);
                doc.setTextColor(...gray);
                const typeLines = wrapText(typeLabel, contentWidth);
                ensureSpace(typeLines.length * 12 + 6);
                doc.text(typeLines, contentX, y + 2, { align });
                y += typeLines.length * 12 + 6;

                const options = q.options || q.possibleResponses || [];
                if (Array.isArray(options) && options.length) {
                    setDocFont("normal");
                    doc.setFontSize(10);
                    doc.setTextColor(...dark);
                    options.forEach((opt) => {
                        const label = typeof opt === "string" ? opt : opt.text || "";
                        const optLines = wrapText(label, contentWidth - 16);
                        ensureSpace(optLines.length * 14);
                        doc.setFillColor(...accent);
                        doc.circle(isRtl ? contentX - 3 : contentX + 3, y - 3.5, 1.6, "F");
                        doc.text(optLines, isRtl ? contentX - 14 : contentX + 14, y, { align });
                        y += optLines.length * 14;
                    });
                }

                y += 26;

                if (index < data.questions.length - 1) {
                    doc.setDrawColor(...lightGray);
                    doc.setLineWidth(0.5);
                    doc.line(contentX, y - 13, isRtl ? margin : pageWidth - margin, y - 13);
                }
            });

            drawFooter();

            const safeTitle = (data.survey?.title || "survey").replace(/[^\p{L}\p{N}-]+/gu, "_");
            doc.save(`${safeTitle}_preview.pdf`);
        } catch (err) {
            console.error("PDF export failed:", err);
        } finally {
            setExporting(false);
        }
    };    const loadingItem = useMemo(() => <TaleLoadingFallback className="py-20" />, []);

    return (
        <div className="min-h-screen bg-white">
            {/* Header */}
            <div className="bg-white rounded-2xl overflow-hidden">
                <div className="pb-0 md:pb-6 p-3 md:p-6">
                    <div className="flex flex-col sm:flex-row items-start justify-between md:mb-6 gap-3">
                        <div className="min-w-0 flex-1">
                            <div className="flex items-start gap-3 mb-3">
                                <button
                                    onClick={() => nav(-1)}
                                    className="w-9 h-9 rounded-xl border-2 border-gray-800 flex items-center justify-center text-gray-500 hover:bg-gray-50 shrink-0"
                                >
                                    <svg className="rtl:-scale-x-100" width="12" height="12" viewBox="0 0 12 12" fill="none" xmlns="http://www.w3.org/2000/svg">
                                        <path d="M5.83333 0.5L0.5 5.83333M0.5 5.83333L5.83333 11.1667M0.5 5.83333H11.1667" stroke="#333333" strokeLinecap="round" strokeLinejoin="round" />
                                    </svg>
                                </button>
                                <div className="min-w-0">
                                    <div className="flex items-center gap-2 mb-1">
                    <span className="inline-flex items-center gap-1.5 px-2.5 py-1 rounded-full bg-blue-50 text-blue-600 text-xs font-semibold">
                      <FiEye className="w-3 h-3" />
                      {t("surveyBuilder.preview.previewMode")}
                    </span>
                                    </div>
                                    <h1 className="text-xl md:text-3xl font-bold text-gray-900 break-words">
                                        {data?.survey?.title}
                                    </h1>
                                </div>
                            </div>
                            <div className="hidden md:flex flex-wrap items-center gap-4 text-gray-600 ml-12 rtl:ml-0 rtl:mr-12">
                                <div className="relative">
                                    <img
                                        alt={data?.company?.companyName || "Company"}
                                        className="w-10 h-10 md:w-12 md:h-12 rounded-full border-2 border-white shadow-lg"
                                        src={
                                            (data?.assets ?? []).find((a) => a.description === "SURVEY_LOGO")?.url ??
                                            data?.company?.assets?.[0]?.url ??
                                            "/assets/survey/respond/no-image.png"
                                        }
                                    />
                                </div>
                                <div className="flex items-center gap-2 text-sm text-gray-600">
                                    <span className="font-medium">{data?.company?.companyName}</span>
                                </div>
                                <div className="flex items-center gap-2">
                                    <FiStar className="w-4 h-4 text-amber-500" />
                                    <span className="font-semibold text-amber-600">
                    {t("home.normal.pointsCount", { count: data?.survey?.rewardPoints || "--" })}
                  </span>
                                </div>
                            </div>
                        </div>

                        <TaleButton
                            onClick={handleExportPdf}
                            loading={exporting}
                            role="normal"
                            variant="outlined"
                            className="!h-11 !rounded-xl shrink-0"
                            startIcon={<FiDownload className="w-4 h-4" />}
                            disabled={loading || !data?.questions?.length}
                        >
                            {t("surveyBuilder.preview.exportPdf")}
                        </TaleButton>
                    </div>

                    {/* Progress */}
                    <div>
                        <div className="flex items-center justify-between text-sm text-gray-600 mb-3">
                            <div className="flex items-center gap-2">
                                <FiClock className="w-4 h-4" />
                                <span>{t("survey.question_of", { current: steps ? currentStep + 1 : 0, total: steps })}</span>
                            </div>
                            <span className="font-semibold">{Math.round(progressPercentage)}%</span>
                        </div>
                        <div className="h-2 bg-gray-200 rounded-full overflow-hidden">
                            <div
                                className="h-full bg-gradient-to-r from-teal-500 to-blue-500 rounded-full transition-all duration-500"
                                style={{ width: `${progressPercentage}%` }}
                            />
                        </div>
                    </div>
                </div>
            </div>

            {/* Question card */}
            <TaleDashbaordMainCard className="md:pt-0 !min-h-0 !rounded-2xl !border-0 overflow-hidden">
                {loading && !error && loadingItem}
                {error && !loading && (
                    <Suspense fallback={loadingItem}>
                        <NotFound />
                    </Suspense>
                )}

                {!loading && !error && !steps && (
                    <div className="flex flex-col items-center justify-center py-20 gap-3 text-gray-500">
                        <FiEye className="w-10 h-10 text-gray-300" />
                        <span>{t("surveyBuilder.preview.noQuestions")}</span>
                    </div>
                )}

                {!loading && !error && !!steps && (
                    <div>
                        <SingleQuestion
                            language={data?.survey?.language}
                            question={formattedQuestion}
                            setQuestion={() => {}}
                            currentIndex={currentStep}
                            questions={data.questions}
                            showCompanyLogo={true}
                            showOptions={false}
                            showProgress={false}
                            totalSteps={steps}
                            company={data.company}
                            state={previewAnswer}
                            setstate={(v) =>
                                setPreviewAnswer((prev) => (typeof v === "function" ? v(prev) : v))
                            }
                            onAutoNext={() => {}}
                        />

                        <div className="md:pt-8 border-t border-gray-200 mt-6">
                            <div className="flex flex-wrap justify-between items-center gap-3">
                                <Button
                                    variant="outlined"
                                    onClick={handlePrevious}
                                    disabled={currentStep === 0}
                                    className="!font-semibold !border-2 !border-gray-300 !text-gray-700 !h-[51px] !min-w-[110px] sm:!min-w-[140px] !rounded-xl !normal-case hover:!border-gray-400 hover:!bg-gray-50 disabled:!opacity-40 transition-all"
                                    startIcon={<FiChevronLeft className="w-4 h-4 rtl:-scale-x-100" />}
                                >
                                    {t("actions.previous")}
                                </Button>

                                <TaleButton
                                    onClick={handleNext}
                                    role="normal"
                                    variant="filled"
                                    disabled={currentStep === steps - 1}
                                    className="!font-semibold !min-w-[110px] sm:!min-w-[140px] !h-[51px] !rounded-xl disabled:!opacity-40"
                                    endIcon={<FiChevronRight className="w-4 h-4 rtl:-scale-x-100" />}
                                >
                                    {t("actions.next")}
                                </TaleButton>
                            </div>
                        </div>
                    </div>
                )}
            </TaleDashbaordMainCard>
        </div>
    );
};

const ErrorWrapped = () => {
    return (
        <ErrorBoundary FallbackComponent={ErrorWrapper} onError={(err, info) => console.log(err, info)}>
            <SurveyPreview />
        </ErrorBoundary>
    );
};

export default ErrorWrapped;