import { createContext, useContext, useEffect, useMemo, useRef, useState } from "react";
import { Platform } from "react-native";
import Constants from "expo-constants";
import AsyncStorage from "@react-native-async-storage/async-storage";
import { type AnalyticsEvent, type Tracker, createHttpSend, createTracker } from "@app/analytics";
import { API_BASE } from "./api";
import { useAuth } from "./auth";
import { BRAND } from "./brand";

function getAppVersion(): string {
  const v = Constants.expoConfig?.version;
  return typeof v === "string" ? v : "unknown";
}

function getLocale(): string {
  const locales = Constants.expoConfig?.locales;
  const first = Array.isArray(locales) ? (locales[0] as unknown) : null;
  return typeof first === "string" ? first : "sv-SE";
}

/**
 * Mobile analytics provider (spec §8.2).
 *
 * v1 limitation: the tracker keeps an in-memory queue only. Events are lost
 * when the app process is killed before the periodic flush. Persisting the
 * queue to AsyncStorage is left for a future iteration.
 */

const ANALYTICS_ENABLED_KEY = `${BRAND.slug}:analytics-enabled`;
const ANALYTICS_ANON_ID_KEY = `${BRAND.slug}:analytics-anon-id`;
const ANALYTICS_SESSION_ID_KEY = `${BRAND.slug}:analytics-session-id`;

interface AnalyticsContextValue {
  track: (event: AnalyticsEvent) => void;
  flush: () => Promise<void>;
  enabled: boolean | null;
  setEnabled: (enabled: boolean) => Promise<void>;
}

const AnalyticsContext = createContext<AnalyticsContextValue | null>(null);

function generateUuid(): string {
  return "xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g, (c) => {
    const r = (Math.random() * 16) | 0;
    const v = c === "x" ? r : (r & 0x3) | 0x8;
    return v.toString(16);
  });
}

async function getOrCreateAnonymousId(): Promise<string> {
  let id = await AsyncStorage.getItem(ANALYTICS_ANON_ID_KEY);
  if (!id) {
    id = generateUuid();
    await AsyncStorage.setItem(ANALYTICS_ANON_ID_KEY, id);
  }
  return id;
}

async function getOrCreateSessionId(): Promise<string> {
  let id = await AsyncStorage.getItem(ANALYTICS_SESSION_ID_KEY);
  if (!id) {
    id = generateUuid();
    await AsyncStorage.setItem(ANALYTICS_SESSION_ID_KEY, id);
  }
  return id;
}

export function AnalyticsProvider({ children }: { children: React.ReactNode }) {
  const accessToken = useAuth((s) => s.accessToken);
  const [enabled, setEnabledState] = useState<boolean | null>(null);
  const [anonymousId, setAnonymousId] = useState<string | null>(null);
  const [sessionId, setSessionId] = useState<string | null>(null);
  const trackerRef = useRef<Tracker | null>(null);

  useEffect(() => {
    void (async () => {
      const [storedEnabled, anon, session] = await Promise.all([
        AsyncStorage.getItem(ANALYTICS_ENABLED_KEY),
        getOrCreateAnonymousId(),
        getOrCreateSessionId(),
      ]);
      // Default to enabled until the user explicitly opts out (GDPR opt-out model).
      setEnabledState(storedEnabled === null ? true : storedEnabled === "true");
      setAnonymousId(anon);
      setSessionId(session);
    })();
  }, []);

  const tracker = useMemo<Tracker | null>(() => {
    if (!anonymousId || !sessionId) return null;
    const send = createHttpSend({ apiBaseUrl: API_BASE, authToken: accessToken ?? undefined });
    return createTracker(
      {
        apiBaseUrl: API_BASE,
        anonymousId,
        sessionId,
        appVersion: getAppVersion(),
        platform: Platform.OS === "ios" ? "ios" : Platform.OS === "android" ? "android" : "web",
        locale: getLocale(),
        maxBatchSize: 20,
        flushIntervalMs: 10_000,
      },
      send,
    );
  }, [anonymousId, sessionId, accessToken]);

  useEffect(() => {
    trackerRef.current = tracker;
    return () => {
      tracker?.destroy();
    };
  }, [tracker]);

  const setEnabled = async (next: boolean) => {
    await AsyncStorage.setItem(ANALYTICS_ENABLED_KEY, String(next));
    setEnabledState(next);
    if (next) {
      await trackerRef.current?.flush();
    }
  };

  const track = (event: AnalyticsEvent) => {
    if (enabled !== true || !trackerRef.current) return;
    trackerRef.current.track(event);
  };

  const flush = async () => {
    await trackerRef.current?.flush();
  };

  const value = useMemo(
    () => ({ track, flush, enabled, setEnabled }),
    // eslint-disable-next-line react-hooks/exhaustive-deps
    [enabled],
  );

  return <AnalyticsContext.Provider value={value}>{children}</AnalyticsContext.Provider>;
}

export function useAnalytics(): AnalyticsContextValue {
  const ctx = useContext(AnalyticsContext);
  if (!ctx) throw new Error("useAnalytics must be used within AnalyticsProvider");
  return ctx;
}
