import { useState, useEffect, useCallback, useMemo } from "react";
import type { XtreamProfile } from "@/types/xtream";
import { nadiDb, migrateLegacyProfiles } from "@/lib/nadiDb";
import { getStoredUser } from "@/lib/nadiAuth";

const ACTIVE_KEY = "nadiplay_active_profile";
const MANAGED_ID_KEY = "nadiplay_managed_profile_id";
const SHARED_ID_PREFIX = "shared:";
const EVENT = "nadiplay-profiles-changed";

/** Sentinel string used as `ownerUserId` for admin-pushed shared
 *  profiles AND the auto-resolved managed profile. NEVER treated as
 *  "owned by user". */
const SHARED_OWNER = "shared";
const MANAGED_OWNER = "managed";

const broadcast = () => window.dispatchEvent(new Event(EVENT));

const loadAll = async (): Promise<XtreamProfile[]> => {
  await migrateLegacyProfiles();
  const list = await nadiDb.profiles.toArray();
  // Back-fill `managed: true` on existing entries that pre-date the
  // flag — locks down older installs after upgrade so users who already
  // had `<name> (NADIPLAYER)` in storage instantly get the creds-hidden
  // treatment.
  let managedId: string | null = null;
  try { managedId = localStorage.getItem(MANAGED_ID_KEY); } catch { /* ignore */ }
  const upgrades: XtreamProfile[] = [];
  for (const p of list) {
    if (p.managed === true && p.ownerUserId) continue;
    const isShared = typeof p.id === "string" && p.id.startsWith(SHARED_ID_PREFIX);
    const isManagedSubscriber = !!managedId && p.id === managedId;
    const nameSuffix = typeof p.name === "string" && p.name.trim().endsWith("(NADIPLAYER)");
    if (isShared || isManagedSubscriber || nameSuffix) {
      upgrades.push({
        ...p,
        managed: true,
        // BUG-6 FIX (2026-05): back-fill ownerUserId so the
        // Owned-vs-Shared filters in useProfiles work for legacy DBs
        // without forcing the user to re-login.
        ownerUserId: p.ownerUserId ?? (isShared ? SHARED_OWNER : MANAGED_OWNER),
      });
    }
  }
  if (upgrades.length > 0) {
    try {
      await nadiDb.profiles.bulkPut(upgrades);
    } catch (e) {
      console.warn("[useProfiles] managed back-fill failed", e);
    }
    return await nadiDb.profiles.toArray();
  }
  return list;
};

/**
 * BUG-6 FIX (2026-05) — owner-scoped cleanup.
 *
 * Deletes any profile in IndexedDB whose `ownerUserId` is set AND
 * differs from the currently-logged-in user id. Called on login so a
 * new account on a shared device sees an empty "Owned" list, exactly
 * as a fresh install would.
 *
 * IMPORTANT — what is preserved:
 *   • Profiles with `ownerUserId === "shared"` (admin-pushed).
 *   • Profiles with `ownerUserId === "managed"` (resolved server creds).
 *   • Profiles with no `ownerUserId` at all (legacy entries — the
 *     back-fill in loadAll() will tag them on next boot).
 */
export const purgeOtherUserProfiles = async (currentUserId: string | null): Promise<number> => {
  try {
    const all = await nadiDb.profiles.toArray();
    let removed = 0;
    for (const p of all) {
      const owner = p.ownerUserId;
      if (!owner) continue; // legacy entry — leave for back-fill
      if (owner === SHARED_OWNER || owner === MANAGED_OWNER) continue;
      if (owner === currentUserId) continue;
      try {
        await nadiDb.profiles.delete(p.id);
        removed += 1;
      } catch (e) {
        console.warn("[useProfiles] purge delete failed for", p.id, e);
      }
    }
    if (removed > 0) {
      console.info(`[useProfiles] purged ${removed} profiles from previous user(s)`);
      broadcast();
    }
    return removed;
  } catch (e) {
    console.warn("[useProfiles] purgeOtherUserProfiles failed", e);
    return 0;
  }
};

export const useProfiles = () => {
  const [profiles, setProfiles] = useState<XtreamProfile[]>([]);
  const [activeProfileId, setActiveIdState] = useState<string | null>(() =>
    localStorage.getItem(ACTIVE_KEY),
  );
  const [currentUserId, setCurrentUserId] = useState<string | null>(
    () => getStoredUser()?.id ?? null,
  );

  // Hydrate from IndexedDB on mount + whenever another tab/window updates.
  const refresh = useCallback(async () => {
    try {
      const list = await loadAll();
      setProfiles(list);
    } catch {
      setProfiles([]);
    }
  }, []);

  useEffect(() => {
    void refresh();
    const sync = () => {
      void refresh();
      setActiveIdState(localStorage.getItem(ACTIVE_KEY));
      // BUG-6 FIX (2026-05): the auth context broadcasts a profile
      // event on login/logout; re-read the currently-logged-in user so
      // the owned/shared filters update immediately.
      setCurrentUserId(getStoredUser()?.id ?? null);
    };
    window.addEventListener(EVENT, sync);
    window.addEventListener("storage", sync);
    return () => {
      window.removeEventListener(EVENT, sync);
      window.removeEventListener("storage", sync);
    };
  }, [refresh]);

  const setActiveProfileId = useCallback((id: string | null) => {
    if (id) localStorage.setItem(ACTIVE_KEY, id);
    else localStorage.removeItem(ACTIVE_KEY);
    setActiveIdState(id);
    broadcast();
  }, []);

  const addProfile = useCallback(
    (profile: Omit<XtreamProfile, "id">): XtreamProfile => {
      // BUG-6 FIX (2026-05): stamp the new profile with the current
      // user id so the Owned-list filter recognises it as the user's
      // own playlist. Falls back to "guest" for not-logged-in sessions
      // so the entry still survives a re-render but doesn't leak into
      // any subsequent user's account.
      const ownerUserId = profile.ownerUserId ?? (currentUserId || "guest");
      const newProfile: XtreamProfile = {
        ...profile,
        ownerUserId,
        id: crypto.randomUUID(),
      };
      // Optimistically update local state, persist async
      setProfiles((prev) => [...prev, newProfile]);
      void nadiDb.profiles
        .put(newProfile)
        .then(() => broadcast())
        .catch((e) => {
          console.error("[nadiDb] failed to persist profile:", e);
        });
      if (!localStorage.getItem(ACTIVE_KEY)) setActiveProfileId(newProfile.id);
      return newProfile;
    },
    [setActiveProfileId, currentUserId],
  );

  const updateProfile = useCallback(
    async (id: string, updates: Partial<Omit<XtreamProfile, "id">>) => {
      setProfiles((prev) =>
        prev.map((p) => (p.id === id ? { ...p, ...updates } : p)),
      );
      try {
        await nadiDb.profiles.update(id, updates);
        broadcast();
      } catch (e) {
        console.error("[nadiDb] update failed:", e);
      }
    },
    [],
  );

  const removeProfile = useCallback(
    async (id: string) => {
      setProfiles((prev) => prev.filter((p) => p.id !== id));
      try {
        await nadiDb.profiles.delete(id);
      } catch (e) {
        console.error("[nadiDb] delete failed:", e);
      }
      if (localStorage.getItem(ACTIVE_KEY) === id) {
        const remaining = await nadiDb.profiles.toArray();
        setActiveProfileId(remaining[0]?.id ?? null);
      }
      broadcast();
    },
    [setActiveProfileId],
  );

  const activeProfile =
    profiles.find((p) => p.id === activeProfileId) ?? null;

  // ── BUG-6 FIX (2026-05): owner-scoped views ─────────────────────────
  // Splits the flat IndexedDB store into THREE virtual lists so the UI
  // can render an "Owned" panel and a "Shared" panel without showing
  // the user another account's profiles. `profiles` (the legacy union
  // list) is kept for backward compatibility with internal callers
  // that still walk every entry (e.g. category prefetchers).
  const ownedProfiles = useMemo(
    () =>
      profiles.filter((p) => {
        if (p.id.startsWith(SHARED_ID_PREFIX)) return false;
        if (p.managed === true) return false;
        const owner = p.ownerUserId;
        if (!owner) return false; // legacy / un-tagged → not OWNED
        if (owner === SHARED_OWNER || owner === MANAGED_OWNER) return false;
        if (!currentUserId) return owner === "guest";
        return owner === currentUserId;
      }),
    [profiles, currentUserId],
  );

  const sharedProfiles = useMemo(
    () =>
      profiles.filter(
        (p) =>
          p.id.startsWith(SHARED_ID_PREFIX) ||
          p.managed === true ||
          p.ownerUserId === SHARED_OWNER ||
          p.ownerUserId === MANAGED_OWNER,
      ),
    [profiles],
  );

  /**
   * Hybrid Engine: Get the best profile for a given section.
   * 1. Look for a profile with matching target ("live" or "vod")
   * 2. Fall back to "all" profiles
   * 3. Fall back to the active profile
   */
  const getProfileForTarget = useCallback(
    (target: "live" | "vod"): XtreamProfile | null => {
      const exact = profiles.find((p) => p.target === target);
      if (exact) return exact;
      const all = profiles.find((p) => !p.target || p.target === "all");
      if (all) return all;
      return activeProfile;
    },
    [profiles, activeProfile],
  );

  const liveProfile = getProfileForTarget("live");
  const vodProfile = getProfileForTarget("vod");

  return {
    profiles,
    /** BUG-6 FIX (2026-05): user-scoped, manually-added playlists. */
    ownedProfiles,
    /** BUG-6 FIX (2026-05): shared:* + admin-pushed managed creds. */
    sharedProfiles,
    activeProfile,
    activeProfileId,
    setActiveProfileId,
    addProfile,
    updateProfile,
    removeProfile,
    liveProfile,
    vodProfile,
    getProfileForTarget,
  };
};
