import { type Component, createMemo, createResource, For, Show } from "solid-js";
import { store, setNoteFilter, getFavoriteTag } from "@/store";
import { pb } from "@/lib/pocketbase";
import { Plus, Lock, Star } from "lucide-solid";
import { Button } from "@/components/ui/button";
import { cn } from "@/lib/utils";
import { NOTES_COLLECTION } from "@/lib/constants";
import { FilterBar } from "./FilterBar";
import { normalizeNoteKey } from "@/lib/tags";

export const NotesSidebar: Component<{
    selectedNoteId: string | null;
    setSelectedNoteId: (id: string | null) => void;
}> = (props) => {
    const currentUserId = pb.authStore.model?.id;
    const [accessibleJobs] = createResource(currentUserId, async (userId) => {
        if (!userId) return new Set<string>();
        try {
            const items = await pb.collection('Job_Info_Prod').getFullList({
                filter: [
                    `EstimatorUser = "${userId}"`,
                    `OfficeRepUser = "${userId}"`,
                    `ProjectManagerUser = "${userId}"`,
                    `Estimator = "${userId}"`,
                    `Office_Rep = "${userId}"`,
                    `Project_Manager = "${userId}"`
                ].join(" || "),
                fields: "id",
                requestKey: null
            });
            return new Set(items.map((r: any) => String(r.id)));
        } catch (e) {
            console.warn("Failed to load job access list for notes filter:", e);
            return new Set<string>();
        }
    });
    const [jobFilterIds] = createResource(
        () => {
            const f = store.noteFilter;
            const normalize = (items: Array<string | { name: string; excluded: boolean }> | undefined) => {
                if (!items) return [] as { name: string; excluded: boolean }[];
                return items.map((i: any) => (typeof i === "string" ? { name: i, excluded: false } : { name: i.name, excluded: !!i.excluded }));
            };
            const status = normalize(f.jobStatus as any).sort((a, b) => a.name.localeCompare(b.name));
            const division = normalize(f.jobDivision as any).sort((a, b) => a.name.localeCompare(b.name));
            const key = JSON.stringify({ status, division });
            return key;
        },
        async (key) => {
            if (!key) return null;
            const parsed = JSON.parse(key) as { status: Array<{ name: string; excluded: boolean }>; division: Array<{ name: string; excluded: boolean }> };
            const status = parsed.status || [];
            const division = parsed.division || [];
            if (status.length === 0 && division.length === 0) return null;

            const parts: string[] = [];
            const statusInclude = status.filter(s => !s.excluded).map(s => s.name);
            const statusExclude = status.filter(s => s.excluded).map(s => s.name);
            const divisionInclude = division.filter(d => !d.excluded).map(d => d.name);
            const divisionExclude = division.filter(d => d.excluded).map(d => d.name);

            if (statusInclude.length > 0) {
                parts.push(`(${statusInclude.map(s => `Job_Status = "${s}"`).join(" || ")})`);
            }
            if (statusExclude.length > 0) {
                parts.push(`(${statusExclude.map(s => `Job_Status != "${s}"`).join(" && ")})`);
            }
            if (divisionInclude.length > 0) {
                parts.push(`(${divisionInclude.map(d => `Job_Division = "${d}"`).join(" || ")})`);
            }
            if (divisionExclude.length > 0) {
                parts.push(`(${divisionExclude.map(d => `Job_Division != "${d}"`).join(" && ")})`);
            }

            const filter = parts.join(" && ");
            try {
                const items = await pb.collection('Job_Info_Prod').getFullList({
                    filter,
                    fields: "id",
                    requestKey: null
                });
                return new Set(items.map((r: any) => String(r.id)));
            } catch (e) {
                console.warn("Failed to load job filter list for notes:", e);
                return new Set<string>();
            }
        }
    );

    const filteredNotes = createMemo(() => {
        const filter = store.noteFilter;
        let n = store.notes.filter(note => {
            if (note.deletedAt) return false;
            // Hide child notes from the main list
            if (note.tags && note.tags.some(t => t.startsWith("child-of-"))) return false;
            return true;
        });

        // Query Filter
        if (filter.query) {
            const q = filter.query.toLowerCase();
            n = n.filter(note =>
                note.title.toLowerCase().includes(q) ||
                note.tags.some(t => t.toLowerCase().includes(q))
            );
        }

        // Tags Filter
        if (filter.tags.length > 0) {
            const required = filter.tags.filter(t => !t.excluded).map(t => t.name);
            const excluded = filter.tags.filter(t => t.excluded).map(t => t.name);

            if (required.length > 0) {
                n = n.filter(note => required.some(r => note.tags.includes(r)));
            }
            if (excluded.length > 0) {
                n = n.filter(note => !excluded.some(e => note.tags.includes(e)));
            }
        }

        // Edited Today Filter
        if (filter.editedToday) {
            const today = new Date();
            today.setHours(0, 0, 0, 0);
            n = n.filter(note => {
                const updated = new Date(note.updated);
                return updated >= today;
            });
        }

        // Owned By Me Filter
        if (filter.ownedByMe) {
            const accessible = accessibleJobs();
            n = n.filter(note => {
                if (note.tags?.includes("prism_job")) {
                    if (!accessible) return false;
                    const jobIdTag = note.tags.find(t => t.startsWith("job_id:"));
                    const jobId = jobIdTag?.split(":")[1]?.trim();
                    if (!jobId) return false;
                    return accessible.has(jobId);
                }
                return note.user === currentUserId;
            });
        }

        // Job Status / Division Filter (notes only)
        if ((filter.jobStatus?.length || 0) > 0 || (filter.jobDivision?.length || 0) > 0) {
            const allowedJobIds = jobFilterIds();
            n = n.filter(note => {
                if (!note.tags?.includes("prism_job")) return false;
                if (!allowedJobIds) return false;
                const jobIdTag = note.tags.find(t => t.startsWith("job_id:"));
                const jobId = jobIdTag?.split(":")[1]?.trim();
                if (!jobId) return false;
                return allowedJobIds.has(jobId);
            });
        }

        // Starred Filter
        if (filter.starred) {
            n = n.filter(note => note.tags?.includes(getFavoriteTag()));
        }

        return n.sort((a, b) => {
            const titleA = a.title || "Untitled";
            const titleB = b.title || "Untitled";
            return titleB.localeCompare(titleA);
        });
    });

    const handleCreateNote = async () => {
        if (!currentUserId) return;
        try {
            const keyBase = normalizeNoteKey("new-note");
            const result = await pb.collection(NOTES_COLLECTION).create({
                title: "New Note",
                key: `${keyBase}-${Date.now()}`,
                content: "",
                tags: [],
                isPrivate: false,
                user: currentUserId,
                tasks: []
            });
            props.setSelectedNoteId(result.id);
        } catch (e) {
            console.error("Failed to create note", e);
        }
    };

    return (
        <div class="flex flex-col h-full bg-card">
            <div class="z-20">
                {/* Header */}
                <div class="p-4 border-b border-border bg-card/50 backdrop-blur flex justify-between items-center gap-2">
                    <div class="flex-1">
                        <input
                            type="text"
                            placeholder="Search notes..."
                            value={store.noteFilter.query}
                            onInput={(e) => setNoteFilter({ query: e.currentTarget.value })}
                            class="w-full bg-muted/30 border border-border/50 rounded-xl px-3 py-2 text-sm outline-none focus:ring-2 focus:ring-primary/20 focus:border-primary/40 transition-all placeholder:text-muted-foreground/30"
                        />
                    </div>
                    <div class="flex items-center gap-2 shrink-0">
                        <FilterBar
                            mode="notes"
                            class="relative top-0 right-0 z-0"
                            triggerClass="h-9 w-9 p-0 bg-muted/40 hover:bg-muted/60 border-border/40"
                        />
                        <Button onClick={handleCreateNote} size="sm" variant="default" class="h-9 w-9 p-0 shrink-0 shadow-sm rounded-xl">
                            <Plus size={18} />
                        </Button>
                    </div>
                </div>
            </div>

            {/* List */}
            <div class="flex-1 overflow-y-auto p-2 space-y-1 pb-20 md:pb-2">
                <For each={filteredNotes()} fallback={<div class="p-4 text-center text-xs text-muted-foreground">{store.isNotesLoading ? "Loading notes..." : "No notes found."}</div>}>
                    {(note) => (
                        <button
                            onClick={() => props.setSelectedNoteId(note.id)}
                            class={cn(
                                "w-full text-left p-3 rounded-xl transition-all border",
                                props.selectedNoteId === note.id
                                    ? "bg-primary/5 border-primary/20 shadow-sm"
                                    : "bg-card border-transparent hover:border-border hover:bg-muted/50"
                            )}
                        >
                            <div class="font-semibold text-sm truncate flex items-center justify-between">
                                <div class="flex items-center gap-1.5 truncate">
                                    <Show when={note.tags?.includes(getFavoriteTag())}>
                                        <Star size={12} class="fill-amber-500 text-amber-500 shrink-0" />
                                    </Show>
                                    <span class="truncate">{note.title || "Untitled"}</span>
                                </div>
                                <Show when={note.isPrivate}>
                                    <Lock size={12} class="text-orange-500 shrink-0 ml-2" />
                                </Show>
                            </div>
                        </button>
                    )}
                </For>
            </div>
        </div>
    );
};
