import { useCallback, useDeferredValue, useEffect, useMemo, useRef, useState } from "react";
import { useAppScope } from "@/app/app-scope/AppScopeProvider.jsx";
import { listGifts, listResourceGroups } from "@/features/resources/api";
import {
    cloneActivityTemplate,
    createActivityTemplate,
    deleteActivityTemplate,
    getActivityTemplate,
    listActivityTemplates,
    listActivityTemplateVersions,
    setActivityTemplateStatus,
    updateActivityTemplate,
    validateActivityTemplate,
} from "@/features/activity-templates/api";
import { useActivityTemplateAbilities } from "@/features/activity-templates/permissions.js";
import {
    activityTemplateFormFromDto,
    activityTemplatePayloadFromForm,
    createEmptyActivityTemplateForm,
} from "@/features/activity-templates/model.js";
import { activityTemplateFormSchema, validateActivityTemplateForPublish } from "@/features/activity-templates/schema";
import { useAdminQuery } from "@/shared/hooks/useAdminQuery.js";
import { useRegionOptions } from "@/shared/hooks/useRegionOptions.js";
import { useConfirm } from "@/shared/ui/ConfirmProvider.jsx";
import { useToast } from "@/shared/ui/ToastProvider.jsx";

const defaultPageSize = 20;
const referencePageSize = 100;
const referenceOptionLimit = 1000;
const emptyPage = { items: [], page: 1, pageSize: defaultPageSize, total: 0 };
const emptyVersions = { items: [], page: 1, pageSize: 20, total: 0 };

export function useActivityTemplatesPage() {
    const { appCode } = useAppScope();
    const activeAppCodeRef = useRef(appCode);
    const previousAppCodeRef = useRef(appCode);
    const abilities = useActivityTemplateAbilities();
    const confirm = useConfirm();
    const { showToast } = useToast();
    const { loadingRegions, regionOptions } = useRegionOptions();
    const [keyword, setKeywordState] = useState("");
    const deferredKeyword = useDeferredValue(keyword.trim());
    const [status, setStatusState] = useState("");
    const [regionId, setRegionIdState] = useState("");
    const [timeRange, setTimeRangeState] = useState({ endMs: "", startMs: "" });
    const [page, setPage] = useState(1);
    const [pageSize, setPageSize] = useState(defaultPageSize);
    const [loadingAction, setLoadingAction] = useState("");
    const [dataSource, setDataSource] = useState(null);
    const [editorMode, setEditorMode] = useState("");

    const filters = useMemo(
        () => ({
            end_ms: timeRange.endMs || undefined,
            keyword: deferredKeyword || undefined,
            page,
            page_size: pageSize,
            region_id: regionId || undefined,
            start_ms: timeRange.startMs || undefined,
            status: status || undefined,
        }),
        [deferredKeyword, page, pageSize, regionId, status, timeRange.endMs, timeRange.startMs],
    );
    const listQueryFn = useCallback(() => listActivityTemplates(filters), [filters]);
    const {
        data = emptyPage,
        error,
        loading,
        reload,
    } = useAdminQuery(listQueryFn, {
        enabled: Boolean(appCode && abilities.canView),
        errorMessage: "加载活动模版失败",
        initialData: emptyPage,
        keepPreviousData: true,
        queryKey: ["activity-templates", appCode, filters],
    });

    const giftQueryFn = useCallback(() => loadActiveReferenceOptions(listGifts), []);
    const { data: giftPage = emptyPage, loading: giftsLoading } = useAdminQuery(giftQueryFn, {
        // 礼物/资源组是可编辑表单的候选项，不属于列表或只读详情依赖。按需加载既降低首屏扇出，
        // 也避免只有 activity-template:view 的运营角色在浏览列表时收到无关跨模块 403。
        enabled: Boolean(appCode && (editorMode === "create" || editorMode === "edit")),
        errorMessage: "加载礼物失败",
        initialData: emptyPage,
        queryKey: ["activity-templates", "gifts", appCode],
        staleTime: 5 * 60 * 1000,
    });
    const resourceGroupQueryFn = useCallback(() => loadActiveReferenceOptions(listResourceGroups), []);
    const { data: resourceGroupPage = emptyPage } = useAdminQuery(resourceGroupQueryFn, {
        enabled: Boolean(appCode && (editorMode === "create" || editorMode === "edit")),
        errorMessage: "加载奖励资源组失败",
        initialData: emptyPage,
        queryKey: ["activity-templates", "resource-groups", appCode],
        staleTime: 5 * 60 * 1000,
    });

    const [editorLoading, setEditorLoading] = useState(false);
    const [form, setForm] = useState(() => createEmptyActivityTemplateForm(appCode));
    const [editorBaseline, setEditorBaseline] = useState(() =>
        formFingerprint(createEmptyActivityTemplateForm(appCode)),
    );
    const [validationIssues, setValidationIssues] = useState([]);
    const editorRequestRef = useRef(0);
    const editorDirty = useMemo(
        () => (editorMode === "create" || editorMode === "edit") && formFingerprint(form) !== editorBaseline,
        [editorBaseline, editorMode, form],
    );

    const resetEditorState = useCallback(() => {
        const emptyForm = createEmptyActivityTemplateForm(appCode);
        editorRequestRef.current += 1;
        setEditorMode("");
        setEditorLoading(false);
        setValidationIssues([]);
        setForm(emptyForm);
        setEditorBaseline(formFingerprint(emptyForm));
    }, [appCode]);

    const closeEditor = useCallback(async () => {
        if (loadingAction.startsWith("save") || loadingAction.startsWith("status:")) return;
        if (editorDirty) {
            const ok = await confirm({
                confirmText: "放弃更改",
                message: "当前活动模版存在未保存更改。",
                title: "关闭活动模版编辑",
                tone: "danger",
            });
            if (!ok) return;
        }
        resetEditorState();
    }, [confirm, editorDirty, loadingAction, resetEditorState]);

    const openCreate = () => {
        const emptyForm = createEmptyActivityTemplateForm(appCode);
        setValidationIssues([]);
        setForm(emptyForm);
        setEditorBaseline(formFingerprint(emptyForm));
        setEditorMode("create");
    };

    const loadEditorTemplate = useCallback(
        async (templateId, mode = "edit") => {
            const requestID = ++editorRequestRef.current;
            setEditorLoading(true);
            setValidationIssues([]);
            setEditorMode(mode);
            try {
                const template = await getActivityTemplate(templateId);
                if (requestID !== editorRequestRef.current || activeAppCodeRef.current !== appCode) return;
                const nextForm = activityTemplateFormFromDto(template, appCode);
                setForm(nextForm);
                setEditorBaseline(formFingerprint(nextForm));
            } catch (err) {
                if (requestID !== editorRequestRef.current) return;
                showToast(err.message || "加载活动模版失败", "error");
                setEditorMode("");
            } finally {
                if (requestID === editorRequestRef.current) setEditorLoading(false);
            }
        },
        [appCode, showToast],
    );

    const openEdit = (item) => {
        // published 对应运行侧不可变快照，编辑入口必须降级为查看；停用成功后再由返回 DTO 打开编辑态。
        void loadEditorTemplate(item.templateId, item.status === "published" ? "view" : "edit");
    };
    const openView = (item) => void loadEditorTemplate(item.templateId, "view");
    const reloadEditor = async () => {
        if (!form.templateId) return;
        if (editorDirty) {
            const ok = await confirm({
                confirmText: "重新加载",
                message: "重新加载将丢弃当前未保存更改。",
                title: "重新加载活动模版",
                tone: "danger",
            });
            if (!ok) return;
        }
        // revision 冲突不能自动覆盖。用户确认放弃本地更改后，再从 owner service
        // 读取最新 revision，避免使用列表缓存或局部合并伪造服务端真实状态。
        await loadEditorTemplate(form.templateId, editorMode === "view" ? "view" : "edit");
    };

    const persistForm = async ({ publish }) => {
        const parsed = activityTemplateFormSchema.safeParse(form);
        if (!parsed.success) {
            const issues = parsed.error.issues.map(toDisplayIssue);
            setValidationIssues(issues);
            showToast(issues[0]?.message || "表单校验失败", "error");
            return null;
        }
        if (publish) {
            const localPublishIssues = validateActivityTemplateForPublish(parsed.data).map((issue) => ({
                code: "publish_required",
                field: issue.path.join("."),
                message: issue.message,
            }));
            if (localPublishIssues.length) {
                setValidationIssues(localPublishIssues);
                showToast(localPublishIssues[0].message, "error");
                return null;
            }
        }
        const payload = activityTemplatePayloadFromForm(parsed.data);
        const operationAppCode = appCode;
        setLoadingAction(publish ? "save-publish" : "save");
        setValidationIssues([]);
        try {
            if (publish) {
                // owner service 返回全部字段问题，先校验可尽早暴露静态错误；最终发布仍可能因排期竞态失败。
                const validation = await validateActivityTemplate(payload, true);
                if (activeAppCodeRef.current !== operationAppCode) return null;
                if (!validation.valid) {
                    setValidationIssues(validation.issues);
                    showToast(validation.issues[0]?.message || "发布校验失败", "error");
                    return null;
                }
            }
            if (activeAppCodeRef.current !== operationAppCode) return null;
            const saved = form.templateId
                ? await updateActivityTemplate(form.templateId, payload, Number(form.revision))
                : await createActivityTemplate(payload);
            if (activeAppCodeRef.current !== operationAppCode) return saved;

            // 保存与发布是两个独立 owner-service 命令。先把保存结果（尤其 template_id/revision）落回表单，
            // 即使随后的发布因排期重叠或竞态失败，也不会在重试时重复 create 或携带旧 revision update。
            const savedForm = activityTemplateFormFromDto(saved, operationAppCode);
            setForm(savedForm);
            setEditorBaseline(formFingerprint(savedForm));
            setEditorMode("edit");

            if (!publish) {
                showToast("活动模版已保存", "success");
                resetEditorState();
                await reload();
                return saved;
            }

            try {
                const published = await setActivityTemplateStatus(saved.templateId, "published", saved.revision);
                if (activeAppCodeRef.current !== operationAppCode) return published;
                showToast("活动模版已发布", "success");
                resetEditorState();
                await reload();
                return published;
            } catch (publishError) {
                if (activeAppCodeRef.current !== operationAppCode) return saved;
                const message = publishError.message || "发布失败";
                setValidationIssues([
                    {
                        code: "publish_failed_after_save",
                        field: "status",
                        message: `草稿已保存，但发布失败：${message}`,
                    },
                ]);
                showToast("草稿已保存，但发布失败", "error");
                await reload();
                return saved;
            }
        } catch (err) {
            if (activeAppCodeRef.current !== operationAppCode) return null;
            // 乐观锁冲突不能自动覆盖：保留当前表单并提供显式重新加载，让运营人员决定如何合并配置。
            const conflict = /revision|conflict|版本|已更新/i.test(err.message || "");
            setValidationIssues([
                {
                    code: conflict ? "revision_conflict" : "save_failed",
                    field: conflict ? "revision" : "",
                    message: conflict ? "模版已被其他管理员更新，请重新加载后再提交" : err.message || "保存失败",
                },
            ]);
            showToast(conflict ? "模版版本已变化" : err.message || "保存失败", "error");
            return null;
        } finally {
            setLoadingAction("");
        }
    };

    const submitForm = (event) => {
        event.preventDefault();
        return persistForm({ publish: false });
    };

    const saveAndPublish = async () => {
        const ok = await confirm({
            confirmText: "保存并发布",
            message: "发布后配置进入只读状态，需先停用才能再次编辑。",
            title: "发布活动模版",
        });
        if (ok) return persistForm({ publish: true });
        return null;
    };

    const changeStatus = async (item, nextStatus, options = {}) => {
        const isPublish = nextStatus === "published";
        const ok =
            options.skipConfirm ||
            (await confirm({
                confirmText: isPublish ? "发布" : "停用",
                message: isPublish
                    ? `${item.name} 将按活动时间和投放区域生效。`
                    : `${item.name} 停用后客户端不再读取该运行配置。`,
                title: isPublish ? "发布活动模版" : "停用活动模版",
                tone: isPublish ? "primary" : "danger",
            }));
        if (!ok) return null;
        setLoadingAction(`status:${item.templateId}`);
        try {
            const updated = await setActivityTemplateStatus(item.templateId, nextStatus, Number(item.revision));
            showToast(isPublish ? "活动模版已发布" : "活动模版已停用", "success");
            await reload();
            return updated;
        } catch (err) {
            showToast(err.message || "状态更新失败", "error");
            return null;
        } finally {
            setLoadingAction("");
        }
    };

    const disableFromEditor = async () => {
        if (!form.templateId || editorMode === "version") return;
        const updated = await changeStatus(
            { name: form.name, revision: form.revision, templateId: form.templateId },
            "disabled",
        );
        if (updated) {
            const nextForm = activityTemplateFormFromDto(updated, appCode);
            setForm(nextForm);
            setEditorBaseline(formFingerprint(nextForm));
            setEditorMode("edit");
            setValidationIssues([]);
        }
    };

    const archiveTemplate = async (item) => {
        const ok = await confirm({
            confirmText: "归档",
            message: `${item.name} 归档后不再出现在默认活动列表中。`,
            title: "归档活动模版",
            tone: "danger",
        });
        if (!ok) return;
        setLoadingAction(`archive:${item.templateId}`);
        try {
            await deleteActivityTemplate(item.templateId, Number(item.revision));
            showToast("活动模版已归档", "success");
            await reload();
        } catch (err) {
            showToast(err.message || "归档失败", "error");
        } finally {
            setLoadingAction("");
        }
    };

    const [cloneSource, setCloneSource] = useState(null);
    const [cloneForm, setCloneForm] = useState({ name: "", sourceVersion: 0, templateCode: "" });
    const openClone = (item, version = null) => {
        const source = version?.snapshot || item;
        setCloneSource(item);
        setCloneForm({
            name: `${source.name || item.name} 副本`,
            sourceVersion: Number(version?.versionNo || 0),
            templateCode: nextCopyCode(source.templateCode || item.templateCode),
        });
    };
    const closeClone = () => {
        if (loadingAction === "clone") return;
        setCloneSource(null);
    };
    const updateCloneForm = (patch) => setCloneForm((current) => ({ ...current, ...patch }));
    const submitClone = async (event) => {
        event.preventDefault();
        if (!cloneSource) return;
        setLoadingAction("clone");
        try {
            await cloneActivityTemplate(cloneSource.templateId, {
                name: cloneForm.name.trim(),
                source_version: Number(cloneForm.sourceVersion || 0),
                template_code: cloneForm.templateCode.trim(),
            });
            setCloneSource(null);
            showToast("活动模版已复制为草稿", "success");
            await reload();
        } catch (err) {
            showToast(err.message || "复制失败", "error");
        } finally {
            setLoadingAction("");
        }
    };

    const [versionSource, setVersionSource] = useState(null);
    const [versionPage, setVersionPage] = useState(1);
    const versionQueryFn = useCallback(
        () => listActivityTemplateVersions(versionSource?.templateId, { page: versionPage, page_size: 20 }),
        [versionPage, versionSource?.templateId],
    );
    const {
        data: versions = emptyVersions,
        error: versionsError,
        loading: versionsLoading,
        reload: reloadVersions,
    } = useAdminQuery(versionQueryFn, {
        enabled: Boolean(versionSource?.templateId),
        errorMessage: "加载发布版本失败",
        initialData: emptyVersions,
        keepPreviousData: true,
        queryKey: ["activity-template-versions", appCode, versionSource?.templateId, versionPage],
    });

    useEffect(() => {
        activeAppCodeRef.current = appCode;
        if (previousAppCodeRef.current === appCode) return;
        previousAppCodeRef.current = appCode;
        const emptyForm = createEmptyActivityTemplateForm(appCode);
        // App header 已先切换请求租户，旧 App 的 overlay 不能继续提交；同时使旧详情请求失效，
        // 防止其晚到响应在新 App 下重新打开旧模版表单。
        editorRequestRef.current += 1;
        setEditorMode("");
        setEditorLoading(false);
        setForm(emptyForm);
        setEditorBaseline(formFingerprint(emptyForm));
        setValidationIssues([]);
        setCloneSource(null);
        setCloneForm({ name: "", sourceVersion: 0, templateCode: "" });
        setVersionSource(null);
        setVersionPage(1);
        setDataSource(null);
        setLoadingAction("");
    }, [appCode]);

    const openVersions = (item) => {
        setVersionPage(1);
        setVersionSource(item);
    };
    const closeVersions = () => setVersionSource(null);
    const previewVersion = (version) => {
        const nextForm = {
            ...activityTemplateFormFromDto(version.snapshot, appCode),
            publishedVersion: version.versionNo,
            status: "published",
        };
        setForm(nextForm);
        setEditorBaseline(formFingerprint(nextForm));
        setVersionSource(null);
        setValidationIssues([]);
        setEditorMode("version");
    };
    const cloneVersion = (version) => {
        const source = versionSource;
        setVersionSource(null);
        openClone(source, version);
    };
    const openData = (item) => setDataSource(item);
    const closeData = () => setDataSource(null);

    const resetFilters = () => {
        setKeywordState("");
        setStatusState("");
        setRegionIdState("");
        setTimeRangeState({ endMs: "", startMs: "" });
        setPage(1);
    };
    const setKeyword = (value) => {
        setKeywordState(value);
        setPage(1);
    };
    const setStatus = (value) => {
        setStatusState(value);
        setPage(1);
    };
    const setRegionId = (value) => {
        setRegionIdState(value);
        setPage(1);
    };
    const setTimeRange = (value) => {
        setTimeRangeState(value);
        setPage(1);
    };
    const changePageSize = (value) => {
        setPageSize(value);
        setPage(1);
    };

    return {
        abilities,
        archiveTemplate,
        changePageSize,
        changeStatus,
        cloneForm,
        cloneSource,
        cloneVersion,
        closeClone,
        closeData,
        closeEditor,
        closeVersions,
        data,
        dataSource,
        disableFromEditor,
        editorLoading,
        editorDirty,
        editorMode,
        error,
        form,
        gifts: giftPage.items || [],
        giftsLoading,
        keyword,
        loading,
        loadingAction,
        loadingRegions,
        openClone,
        openCreate,
        openData,
        openEdit,
        openVersions,
        openView,
        page,
        pageSize,
        previewVersion,
        regionId,
        regionOptions,
        reload,
        reloadEditor,
        reloadVersions,
        resetFilters,
        resourceGroups: resourceGroupPage.items || [],
        saveAndPublish,
        setForm,
        setKeyword,
        setPage,
        setRegionId,
        setStatus,
        setTimeRange,
        setVersionPage,
        status,
        submitClone,
        submitForm,
        timeRange,
        updateCloneForm,
        validationIssues,
        versionPage,
        versionSource,
        versions,
        versionsError,
        versionsLoading,
    };
}

function toDisplayIssue(issue) {
    return {
        code: issue.code || "invalid",
        field: issue.path.join("."),
        message: issue.message,
    };
}

export function nextCopyCode(value, now = Date.now(), entropy = Math.random()) {
    const base = String(value || "activity")
        .toLowerCase()
        .replace(/[^a-z0-9_-]/g, "_")
        .replace(/^([^a-z])+/, "a_")
        .slice(0, 40);
    const timestamp = new Date(now).toISOString().slice(2, 19).replace(/[-T:]/g, "");
    const random = Math.floor(Math.max(0, Math.min(0.999999, entropy)) * 36 ** 4)
        .toString(36)
        .padStart(4, "0");
    return `${base}_copy_${timestamp}_${random}`.slice(0, 64);
}

export function formFingerprint(value) {
    return JSON.stringify(value);
}

export async function loadActiveReferenceOptions(fetchPage, maxItems = referenceOptionLimit) {
    const safeLimit = Math.max(1, Math.min(referenceOptionLimit, Number(maxItems) || referenceOptionLimit));
    const items = [];
    let page = 1;
    let ownerTotal = 0;

    // wallet-service 将 page_size 上限固定为 100。逐页读取到 total 或本模块的安全上限，
    // 让礼物/资源组抽屉可以搜索完整候选项，同时避免用错误的 300 条回显推导下一页。
    while (items.length < safeLimit) {
        const result = await fetchPage({ page, page_size: referencePageSize, status: "active" });
        const pageItems = Array.isArray(result?.items) ? result.items : [];
        ownerTotal = Math.max(ownerTotal, Number(result?.total) || 0);
        items.push(...pageItems.slice(0, safeLimit - items.length));

        const reachedOwnerTotal = ownerTotal > 0 && items.length >= ownerTotal;
        const reachedLastPage = pageItems.length < referencePageSize;
        if (reachedOwnerTotal || reachedLastPage || items.length >= safeLimit) break;
        page += 1;
    }

    return {
        items,
        page: 1,
        pageSize: referencePageSize,
        total: ownerTotal || items.length,
    };
}
