'use client';
import { useCallback, useEffect, useMemo, useState } from 'react';
import { cmsApi } from '../../lib/api.js';
const EMPTY_FORM = {
    siteTitle: '',
    tagline: '',
    siteUrl: '',
    language: 'en',
    timezone: 'UTC',
    defaultNoIndex: false,
    defaultNoFollow: false,
    noIndexNonProduction: false,
};
/** Validate a site URL: absolute http(s), no trailing slash, parseable. */
export function validateSiteUrl(value) {
    const trimmed = value.trim();
    if (!trimmed)
        return { valid: true };
    let url;
    try {
        url = new URL(trimmed);
    }
    catch {
        return { valid: false, error: 'Enter a valid absolute URL, e.g. https://example.com' };
    }
    if (url.protocol !== 'http:' && url.protocol !== 'https:') {
        return { valid: false, error: 'Site URL must start with http:// or https://' };
    }
    if (trimmed.endsWith('/')) {
        return { valid: false, error: 'Remove the trailing slash (e.g. https://example.com)' };
    }
    return { valid: true };
}
/** Best-effort IANA timezone check using the Intl API. */
export function isValidTimeZone(tz) {
    if (!tz)
        return false;
    try {
        new Intl.DateTimeFormat('en-US', { timeZone: tz });
        return true;
    }
    catch {
        return false;
    }
}
/** Best-effort BCP 47 locale check. */
export function isValidLocale(locale) {
    if (!locale)
        return false;
    try {
        // Throws RangeError on structurally invalid tags.
        new Intl.Locale(locale);
        return /^[a-zA-Z]{2,3}([-_][a-zA-Z0-9]{2,8})*$/.test(locale);
    }
    catch {
        return false;
    }
}
function validate(form, isProduction) {
    const issues = [];
    if (!form.siteTitle.trim()) {
        issues.push({ field: 'siteTitle', message: 'Site Title is required.', severity: 'error' });
    }
    const urlCheck = validateSiteUrl(form.siteUrl);
    if (!urlCheck.valid) {
        issues.push({ field: 'siteUrl', message: urlCheck.error, severity: 'error' });
    }
    else if (!form.siteUrl.trim() && isProduction) {
        issues.push({
            field: 'siteUrl',
            message: 'Site URL is not set — canonical, sitemap, and Open Graph URLs may be invalid.',
            severity: 'warning',
        });
    }
    if (!isValidLocale(form.language)) {
        issues.push({
            field: 'language',
            message: 'Language must be a valid locale code, e.g. en-US.',
            severity: 'error',
        });
    }
    if (!isValidTimeZone(form.timezone)) {
        issues.push({
            field: 'timezone',
            message: 'Timezone must be a valid IANA name, e.g. America/Los_Angeles.',
            severity: 'error',
        });
    }
    return issues;
}
/**
 * Loads the General tab from its three real backends — the `settings` global
 * (site info / locale), the shared `/seo/config` (site URL + robots defaults),
 * and the computed `/seo/index-status` — tracks a dirty diff, and on save
 * writes each field back to its OWNING store (never a duplicate), preserving
 * unrelated keys.
 */
export function useGeneralSettings(canEdit) {
    const [loading, setLoading] = useState(true);
    const [loadError, setLoadError] = useState(null);
    const [baseline, setBaseline] = useState(EMPTY_FORM);
    const [form, setForm] = useState(EMPTY_FORM);
    const [indexStatus, setIndexStatus] = useState(null);
    const [sources, setSources] = useState({});
    // Full settings-global blob so a partial save never wipes AI/security keys.
    const [settingsBlob, setSettingsBlob] = useState({});
    const [overrideSite, setOverrideSite] = useState({});
    const [saveState, setSaveState] = useState('idle');
    const [saveError, setSaveError] = useState(null);
    const [reloadKey, setReloadKey] = useState(0);
    useEffect(() => {
        let cancelled = false;
        setLoading(true);
        setLoadError(null);
        Promise.all([
            cmsApi('/globals/settings'),
            cmsApi('/seo/config'),
            cmsApi('/seo/index-status'),
        ])
            .then(([settingsRes, seoRes, statusRes]) => {
            if (cancelled)
                return;
            if (settingsRes.error && settingsRes.status !== 404) {
                setLoadError(settingsRes.error);
            }
            const settingsData = settingsRes.data ?? {};
            const seo = seoRes.data ?? {};
            const effectiveSite = seo.effective?.site ?? {};
            const staticSite = seo.static?.site ?? {};
            const overSite = seo.overrides?.site ?? {};
            const robots = effectiveSite.robots ?? {};
            const loaded = {
                siteTitle: String(settingsData.siteTitle ?? ''),
                tagline: String(settingsData.tagline ?? ''),
                siteUrl: String(effectiveSite.siteUrl ?? settingsData.siteUrl ?? ''),
                language: String(settingsData.language ?? 'en'),
                timezone: String(settingsData.timezone ?? 'UTC'),
                defaultNoIndex: robots.defaultNoIndex === true,
                defaultNoFollow: robots.defaultNoFollow === true,
                noIndexNonProduction: robots.noIndexNonProduction === true,
            };
            // Site URL is config-managed when actuate.config.ts supplies it.
            const siteUrlFromConfig = Boolean(staticSite.siteUrl);
            setSources({
                siteUrl: siteUrlFromConfig
                    ? { source: 'config', editable: false, reason: 'Set in actuate.config.ts' }
                    : { source: 'database', editable: canEdit },
                siteTitle: { source: 'database', editable: canEdit },
                tagline: { source: 'database', editable: canEdit },
                language: { source: 'database', editable: canEdit },
                timezone: { source: 'database', editable: canEdit },
                seoDefaults: {
                    source: 'plugin',
                    editable: canEdit,
                    reason: 'Shared with the SEO section',
                },
            });
            setBaseline(loaded);
            setForm(loaded);
            setSettingsBlob(settingsData);
            setOverrideSite(overSite ?? {});
            if (!seoRes.error && statusRes.data)
                setIndexStatus(statusRes.data);
        })
            .catch(() => {
            if (!cancelled)
                setLoadError('Failed to load settings.');
        })
            .finally(() => {
            if (!cancelled)
                setLoading(false);
        });
        return () => {
            cancelled = true;
        };
    }, [reloadKey, canEdit]);
    const setField = useCallback((key, value) => {
        setForm((prev) => ({ ...prev, [key]: value }));
        setSaveState('idle');
    }, []);
    const isProduction = (indexStatus?.environment ?? '') === 'production';
    const dirty = useMemo(() => Object.keys(form).some((k) => form[k] !== baseline[k]), [form, baseline]);
    const issues = useMemo(() => validate(form, isProduction), [form, isProduction]);
    const hasErrors = issues.some((i) => i.severity === 'error');
    const refetchStatus = useCallback(async () => {
        const res = await cmsApi('/seo/index-status');
        if (!res.error && res.data)
            setIndexStatus(res.data);
    }, []);
    const save = useCallback(async () => {
        if (!canEdit || hasErrors)
            return;
        setSaveState('saving');
        setSaveError(null);
        const siteUrlEditable = sources.siteUrl?.editable !== false;
        const siteInfoChanged = form.siteTitle !== baseline.siteTitle ||
            form.tagline !== baseline.tagline ||
            form.language !== baseline.language ||
            form.timezone !== baseline.timezone;
        const siteUrlChanged = siteUrlEditable && form.siteUrl !== baseline.siteUrl;
        const robotsChanged = form.defaultNoIndex !== baseline.defaultNoIndex ||
            form.defaultNoFollow !== baseline.defaultNoFollow ||
            form.noIndexNonProduction !== baseline.noIndexNonProduction;
        try {
            // 1. Site info → the `settings` global (preserve AI/security/layout keys,
            //    and drop legacy robots/siteUrl duplicates so SEO config owns them).
            //    Read-modify-write against a fresh fetch so a concurrent save from the
            //    Security/AI tabs (same global blob) is never clobbered.
            if (siteInfoChanged) {
                const current = await cmsApi('/globals/settings');
                const blob = { ...(current.data ?? settingsBlob) };
                delete blob.defaultNoIndex;
                delete blob.defaultNoFollow;
                delete blob.noIndexNonProduction;
                delete blob.siteUrl;
                const payload = {
                    ...blob,
                    siteTitle: form.siteTitle.trim(),
                    tagline: form.tagline.trim(),
                    language: form.language,
                    timezone: form.timezone,
                };
                const res = await cmsApi('/globals/settings', {
                    method: 'PUT',
                    body: JSON.stringify(payload),
                });
                if (res.error)
                    throw new Error(res.error);
                setSettingsBlob(payload);
            }
            // 2. Site URL + robots defaults → the SHARED SEO config (merge over the
            //    current override site so SEO-tab fields aren't lost).
            if (siteUrlChanged || robotsChanged) {
                const nextSite = { ...overrideSite };
                if (siteUrlChanged)
                    nextSite.siteUrl = form.siteUrl.trim() || undefined;
                if (robotsChanged) {
                    nextSite.robots = {
                        ...(overrideSite.robots ?? {}),
                        defaultNoIndex: form.defaultNoIndex,
                        defaultNoFollow: form.defaultNoFollow,
                        noIndexNonProduction: form.noIndexNonProduction,
                    };
                }
                const res = await cmsApi('/seo/config', {
                    method: 'PUT',
                    body: JSON.stringify({ site: nextSite }),
                });
                if (res.error)
                    throw new Error(res.error);
                setOverrideSite(nextSite);
            }
            setBaseline(form);
            setSaveState('success');
            await refetchStatus();
        }
        catch (err) {
            setSaveState('error');
            setSaveError(err instanceof Error ? err.message : 'Failed to save settings.');
        }
    }, [canEdit, hasErrors, form, baseline, settingsBlob, overrideSite, sources, refetchStatus]);
    const reset = useCallback(() => {
        setForm(baseline);
        setSaveState('idle');
        setSaveError(null);
    }, [baseline]);
    const refetch = useCallback(() => setReloadKey((k) => k + 1), []);
    return {
        loading,
        loadError,
        form,
        setField,
        dirty,
        issues,
        hasErrors,
        indexStatus,
        sources,
        isProduction,
        saveState,
        saveError,
        save,
        reset,
        refetch,
    };
}
//# sourceMappingURL=useGeneralSettings.js.map