import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
import { useEffect, useState } from "react";
import { Check, ChevronDown, ChevronRight, Pencil, Plus } from "lucide-react";
import { Button } from "../../components/ui/button";
import { DeleteIcon } from "../../components/ui/delete-icon";
import { Input } from "../../components/ui/input";
import { Select } from "../../components/ui/select";
import { useEditContext } from "../../editor/client/editContext";
import { ItemCollectionPicker, isGuid } from "./ItemCollectionPicker";
import { deleteProjectProperty, getItemCollectionSummary, getProjectProperties, upsertProjectProperties, } from "../services/taskService";
const HIDDEN_PROJECT_PROPERTY_KEYS = new Set(["taskboard.graphLayout.v1"]);
function formatValueType(valueType) {
    return valueType === "itemCollectionRef" ? "Item Collection" : "String";
}
function formatCollectionSummary(summary) {
    const countLabel = `${summary.itemCount} ${summary.itemCount === 1 ? "item" : "items"}`;
    if (summary.name)
        return `${summary.name} (${countLabel})`;
    if (!summary.itemNames?.length)
        return `Empty collection (${countLabel})`;
    const list = summary.itemNames.join(", ");
    const preview = summary.hasMore ? `${list}...` : list;
    return `${preview} (${countLabel})`;
}
function PropertyValuePreview({ draft }) {
    const [summary, setSummary] = useState(null);
    const itemCollectionId = draft.itemCollectionId.trim();
    const hasValidCollection = draft.valueType === "itemCollectionRef" && isGuid(itemCollectionId);
    useEffect(() => {
        if (!hasValidCollection) {
            setSummary(null);
            return;
        }
        let disposed = false;
        getItemCollectionSummary(itemCollectionId).then((result) => {
            if (disposed)
                return;
            setSummary(result.type === "success" && result.data ? result.data : null);
        });
        return () => {
            disposed = true;
        };
    }, [hasValidCollection, itemCollectionId]);
    if (draft.valueType === "itemCollectionRef") {
        const label = hasValidCollection
            ? summary
                ? formatCollectionSummary(summary)
                : "Loading collection..."
            : itemCollectionId || "No collection selected";
        return (_jsx("span", { className: "text-neutral-grey-100 block truncate text-xs", title: label, children: label }));
    }
    const value = draft.stringValue || "Empty string";
    return (_jsx("span", { className: `block truncate text-xs ${draft.stringValue ? "text-neutral-grey-100" : "text-neutral-grey-50"}`, title: draft.stringValue || undefined, children: value }));
}
function toDrafts(properties) {
    return properties
        .filter((property) => !HIDDEN_PROJECT_PROPERTY_KEYS.has(property.propertyKey))
        .map((property) => ({
        localId: property.propertyId || `${property.projectId}-${property.propertyKey}`,
        persisted: true,
        propertyKey: property.propertyKey,
        valueType: property.valueType,
        stringValue: property.stringValue ?? "",
        itemCollectionId: property.itemCollectionId ?? "",
    }));
}
export function ProjectPropertiesPanel(props) {
    const { projectId, canEdit, className, defaultExpanded = false, showHeader = true, } = props;
    const editContext = useEditContext();
    const [drafts, setDrafts] = useState([]);
    const [loading, setLoading] = useState(false);
    const [savingLocalId, setSavingLocalId] = useState(null);
    const [editingLocalIds, setEditingLocalIds] = useState(new Set());
    const [error, setError] = useState(null);
    const [expanded, setExpanded] = useState(defaultExpanded);
    useEffect(() => {
        setExpanded(defaultExpanded);
    }, [defaultExpanded, projectId]);
    useEffect(() => {
        let disposed = false;
        async function load() {
            if (!projectId)
                return;
            setLoading(true);
            setError(null);
            try {
                const result = await getProjectProperties(projectId);
                if (disposed)
                    return;
                if (result.type === "success") {
                    setDrafts(toDrafts(result.data || []));
                    return;
                }
                setError(result.summary || "Failed to load project properties");
            }
            catch (requestError) {
                if (!disposed) {
                    setError(requestError instanceof Error
                        ? requestError.message
                        : "Failed to load project properties");
                }
            }
            finally {
                if (!disposed) {
                    setLoading(false);
                }
            }
        }
        void load();
        return () => {
            disposed = true;
        };
    }, [projectId]);
    useEffect(() => {
        const addListener = editContext?.addSocketMessageListener;
        if (!addListener || !projectId)
            return;
        const unsubscribe = addListener((message) => {
            if (message?.type !== "project:properties:updated")
                return;
            const payload = message?.payload ?? {};
            const msgProjectId = payload.projectId;
            if (msgProjectId !== projectId)
                return;
            void getProjectProperties(projectId).then((result) => {
                if (result.type === "success") {
                    setDrafts(toDrafts(result.data || []));
                    setEditingLocalIds(new Set());
                }
            });
        });
        return () => unsubscribe();
    }, [editContext, projectId]);
    function isRowValid(draft) {
        const key = draft.propertyKey.trim();
        if (!key)
            return false;
        if (draft.valueType === "itemCollectionRef")
            return isGuid(draft.itemCollectionId);
        return draft.stringValue != null;
    }
    function updateDraft(localId, patch) {
        setDrafts((current) => current.map((draft) => draft.localId === localId ? { ...draft, ...patch } : draft));
    }
    function addDraft() {
        const localId = `new-${Date.now()}-${Math.random().toString(36).slice(2, 8)}`;
        setDrafts((current) => [
            ...current,
            {
                localId,
                persisted: false,
                propertyKey: "",
                valueType: "string",
                stringValue: "",
                itemCollectionId: "",
            },
        ]);
        setEditingLocalIds((prev) => new Set([...prev, localId]));
    }
    function startEditing(localId) {
        setEditingLocalIds((prev) => new Set([...prev, localId]));
    }
    async function removeRow(localId) {
        const draft = drafts.find((d) => d.localId === localId);
        if (!draft || !projectId)
            return;
        const remaining = drafts.filter((d) => d.localId !== localId);
        setError(null);
        if (draft.persisted) {
            setSavingLocalId(localId);
            try {
                const result = await deleteProjectProperty({
                    projectId,
                    propertyKey: draft.propertyKey.trim(),
                });
                if (result.type === "success") {
                    setDrafts(toDrafts(result.data || []));
                    setEditingLocalIds((prev) => {
                        const next = new Set(prev);
                        next.delete(localId);
                        return next;
                    });
                }
                else {
                    setError(result.summary || "Failed to delete property");
                }
            }
            catch (requestError) {
                setError(requestError instanceof Error
                    ? requestError.message
                    : "Failed to delete property");
            }
            finally {
                setSavingLocalId(null);
            }
        }
        else {
            setDrafts(remaining);
            setEditingLocalIds((prev) => {
                const next = new Set(prev);
                next.delete(localId);
                return next;
            });
        }
    }
    async function commitRow(localId) {
        if (!projectId)
            return;
        const draft = drafts.find((d) => d.localId === localId);
        if (!draft)
            return;
        if (!isRowValid(draft)) {
            setError("Key required; use valid GUID for Item Collection.");
            return;
        }
        setSavingLocalId(localId);
        setError(null);
        const properties = [];
        for (const d of drafts) {
            const propertyKey = d.propertyKey.trim();
            if (!propertyKey)
                continue;
            if (d.valueType === "itemCollectionRef") {
                properties.push({
                    propertyKey,
                    valueType: "itemCollectionRef",
                    itemCollectionId: d.itemCollectionId.trim(),
                });
            }
            else {
                properties.push({
                    propertyKey,
                    valueType: "string",
                    stringValue: d.stringValue ?? "",
                });
            }
        }
        const request = { projectId, properties };
        try {
            const result = await upsertProjectProperties(request);
            if (result.type === "success") {
                setDrafts(toDrafts(result.data || []));
                setEditingLocalIds((prev) => {
                    const next = new Set(prev);
                    next.delete(localId);
                    return next;
                });
            }
            else {
                setError(result.summary || "Failed to save project properties");
            }
        }
        catch (requestError) {
            setError(requestError instanceof Error
                ? requestError.message
                : "Failed to save project properties");
        }
        finally {
            setSavingLocalId(null);
        }
    }
    return (_jsxs("div", { className: `${className || ""} max-w-[1000px]`, children: [showHeader ? (_jsx("div", { className: "hover:bg-neutral-grey-5 mb-2 flex cursor-pointer items-center justify-between gap-2 rounded-md transition-colors", onClick: () => setExpanded((e) => !e), onKeyDown: (e) => {
                    if (e.key === "Enter" || e.key === " ") {
                        e.preventDefault();
                        setExpanded((prev) => !prev);
                    }
                }, role: "button", tabIndex: 0, "aria-expanded": expanded, "aria-controls": "project-properties-content", id: "project-properties-header", "data-testid": "taskboard-project-properties-header", children: _jsxs("div", { className: "flex min-w-0 flex-1 items-center gap-1.5", children: [expanded ? (_jsx(ChevronDown, { className: "text-neutral-grey-50 h-4 w-4 shrink-0" })) : (_jsx(ChevronRight, { className: "text-neutral-grey-50 h-4 w-4 shrink-0" })), _jsxs("div", { className: "min-w-0", children: [_jsx("div", { className: "text-neutral-grey-50 text-[11px] font-medium tracking-wider", children: "Project Properties" }), expanded ? (_jsx("div", { className: "text-neutral-grey-50 text-xs", children: "Shared key/value context for task agents. (e.g. productScope)." })) : (_jsxs("div", { className: "text-neutral-grey-50 text-xs", children: [drafts.length, " ", drafts.length === 1 ? "property" : "properties"] }))] })] }) })) : null, (showHeader ? expanded : true) && (_jsxs("div", { id: "project-properties-content", "aria-labelledby": showHeader ? "project-properties-header" : undefined, children: [loading ? (_jsx("div", { className: "text-neutral-grey-50 text-xs", children: "Loading properties..." })) : null, error ? (_jsx("div", { className: "text-feedback-red mb-2 text-xs", children: error })) : null, drafts.length === 0 ? (_jsx("div", { className: "border-border-default text-neutral-grey-50 rounded-md border border-dashed p-3 text-xs", children: "No properties yet." })) : (_jsxs("div", { className: "overflow-hidden rounded-md bg-white", children: [_jsxs("div", { className: "border-border-default/70 text-neutral-grey-50 hidden grid-cols-[minmax(0,1.1fr)_130px_minmax(0,1.3fr)_auto] gap-3 border-b bg-white px-3 py-1.5 text-xs font-normal tracking-wider md:grid", children: [_jsx("span", { children: "Key" }), _jsx("span", { children: "Type" }), _jsx("span", { children: "Value" }), _jsx("span", { className: "w-16 text-right", children: "Actions" })] }), drafts.map((draft) => {
                                const isEditing = editingLocalIds.has(draft.localId);
                                const isSaving = savingLocalId === draft.localId;
                                const rowDisabled = !canEdit || isSaving;
                                const canCommit = isRowValid(draft);
                                if (!isEditing) {
                                    return (_jsxs("div", { className: "group border-border-default/70 hover:bg-neutral-grey-5/35 grid grid-cols-[minmax(0,1fr)_auto] items-center gap-x-3 gap-y-1 border-t bg-white px-3 py-2.5 transition-colors first:border-t-0 md:grid-cols-[minmax(0,1.1fr)_130px_minmax(0,1.3fr)_auto]", children: [_jsxs("div", { className: "min-w-0", children: [_jsx("div", { className: "text-neutral-grey-100 truncate text-xs font-medium", title: draft.propertyKey, children: draft.propertyKey }), _jsx("div", { className: "text-neutral-grey-50 mt-0.5 text-[11px] md:hidden", children: formatValueType(draft.valueType) })] }), _jsx("div", { className: "hidden min-w-0 md:block", children: _jsx("span", { className: "text-neutral-grey-50 truncate text-xs", children: formatValueType(draft.valueType) }) }), _jsx("div", { className: "col-start-1 row-start-2 min-w-0 md:col-start-auto md:row-start-auto", children: _jsx(PropertyValuePreview, { draft: draft }) }), _jsxs("div", { className: "col-start-2 row-start-1 flex shrink-0 items-center justify-end gap-0.5 opacity-0 transition-opacity group-focus-within:opacity-100 group-hover:opacity-100 md:col-start-auto md:row-auto", children: [_jsx(Button, { size: "icon", variant: "ghost", className: "text-neutral-grey-50 hover:text-neutral-grey-100 h-7 w-7", onClick: () => startEditing(draft.localId), disabled: rowDisabled, title: "Edit", "data-testid": `taskboard-project-properties-edit-${draft.localId}`, children: _jsx(Pencil, { className: "h-3 w-3" }) }), _jsx(Button, { size: "icon", variant: "ghost", className: "text-neutral-grey-50 hover:bg-neutral-grey-5 hover:text-neutral-grey-50 h-7 w-7", onClick: () => void removeRow(draft.localId), disabled: rowDisabled || savingLocalId === draft.localId, title: "Delete", "data-testid": `taskboard-project-properties-delete-${draft.localId}`, children: savingLocalId === draft.localId &&
                                                            draft.persisted ? (_jsx("span", { className: "h-3 w-3 animate-spin rounded-full border border-current border-t-transparent" })) : (_jsx(DeleteIcon, { size: "sm" })) })] })] }, draft.localId));
                                }
                                return (_jsxs("div", { className: "border-border-default/70 grid grid-cols-[minmax(0,1fr)_auto] items-start gap-2 border-t bg-white px-3 py-2.5 first:border-t-0 md:grid-cols-[minmax(0,1.1fr)_130px_minmax(0,1.3fr)_auto]", children: [_jsx(Input, { value: draft.propertyKey, disabled: rowDisabled, onChange: (event) => updateDraft(draft.localId, {
                                                propertyKey: event.target.value,
                                            }), placeholder: "e.g. productScope (camelCase)", className: "bg-neutral-grey-5 h-7 text-xs" }), _jsx(Select, { value: draft.valueType, disabled: rowDisabled, onValueChange: (value) => updateDraft(draft.localId, {
                                                valueType: value,
                                                stringValue: value === "itemCollectionRef"
                                                    ? draft.stringValue
                                                    : draft.stringValue,
                                                itemCollectionId: value === "itemCollectionRef"
                                                    ? draft.itemCollectionId
                                                    : "",
                                            }), options: [
                                                { value: "string", label: "String" },
                                                {
                                                    value: "itemCollectionRef",
                                                    label: "Item Collection",
                                                },
                                            ], className: "bg-white col-span-2 h-7 text-xs md:col-span-1" }), draft.valueType === "itemCollectionRef" ? (_jsx("div", { className: "col-span-2 min-w-0 md:col-span-1", children: _jsx(ItemCollectionPicker, { value: draft.itemCollectionId, disabled: rowDisabled, onChange: (nextValue) => updateDraft(draft.localId, {
                                                    itemCollectionId: nextValue,
                                                }), compact: true, displayNameOnly: true }) })) : (_jsx(Input, { value: draft.stringValue, disabled: rowDisabled, onChange: (event) => updateDraft(draft.localId, {
                                                stringValue: event.target.value,
                                            }), placeholder: "String value", className: "bg-neutral-grey-5 col-span-2 h-7 text-xs md:col-span-1" })), _jsxs("div", { className: "col-start-2 row-start-1 flex shrink-0 items-center justify-end gap-0.5 md:col-start-auto md:row-auto", children: [_jsx(Button, { size: "icon", variant: "ghost", className: "text-neutral-grey-50 hover:text-neutral-grey-100 h-7 w-7", onClick: () => void commitRow(draft.localId), disabled: rowDisabled || !canCommit, title: "Commit", "data-testid": `taskboard-project-properties-commit-${draft.localId}`, children: isSaving ? (_jsx("span", { className: "h-3 w-3 animate-spin rounded-full border border-current border-t-transparent" })) : (_jsx(Check, { className: "h-3 w-3" })) }), _jsx(Button, { size: "icon", variant: "ghost", className: "text-neutral-grey-50 hover:bg-neutral-grey-5 hover:text-neutral-grey-50 h-7 w-7", onClick: () => void removeRow(draft.localId), disabled: rowDisabled || savingLocalId === draft.localId, title: "Delete", "data-testid": `taskboard-project-properties-delete-${draft.localId}`, children: savingLocalId === draft.localId && draft.persisted ? (_jsx("span", { className: "h-3 w-3 animate-spin rounded-full border border-current border-t-transparent" })) : (_jsx(DeleteIcon, { size: "sm" })) })] })] }, draft.localId));
                            })] })), _jsxs(Button, { size: "xs", variant: "secondary", onClick: addDraft, disabled: !canEdit || loading, className: "mt-3", "data-testid": "taskboard-project-properties-add", children: [_jsx(Plus, { className: "h-3 w-3" }), "Add"] })] }))] }));
}
//# sourceMappingURL=ProjectPropertiesPanel.js.map