import AsyncStorage from "@react-native-async-storage/async-storage";
import React, {
  createContext,
  useCallback,
  useContext,
  useEffect,
  useMemo,
  useState,
} from "react";

import {
  AffiliateLink,
  Generation,
  Payout,
  Persona,
  Transaction,
  commissionForMerchant,
  detectMerchant,
  genId,
  profile as defaultProfile,
  seedGenerations,
  seedLinks,
  seedPayouts,
  seedPersonas,
  seedTransactions,
  shortCode,
} from "@/constants/mockData";

type Profile = typeof defaultProfile;

interface AppState {
  profile: Profile;
  links: AffiliateLink[];
  transactions: Transaction[];
  payouts: Payout[];
  personas: Persona[];
  generations: Generation[];
  totals: {
    pending: number;
    confirmed: number;
    due: number;
    paid: number;
    available: number;
  };
  convertLink: (
    url: string,
    subId?: string,
    productTitle?: string,
  ) => AffiliateLink;
  requestPayout: (
    amount: number,
    method: "UPI" | "IMPS",
    account: string,
  ) => Payout;
  addPersona: (name: string, imageCount: number) => Persona;
  addGeneration: (g: Omit<Generation, "id" | "createdAt">) => Generation;
  setKycStatus: (status: Profile["kycStatus"]) => void;
}

const AppContext = createContext<AppState | undefined>(undefined);

const STORAGE_KEY = "edgegen.state.v1";

interface PersistShape {
  profile: Profile;
  links: AffiliateLink[];
  transactions: Transaction[];
  payouts: Payout[];
  personas: Persona[];
  generations: Generation[];
}

export function AppProvider({ children }: { children: React.ReactNode }) {
  const [profile, setProfile] = useState<Profile>(defaultProfile);
  const [links, setLinks] = useState<AffiliateLink[]>(seedLinks);
  const [transactions, setTransactions] =
    useState<Transaction[]>(seedTransactions);
  const [payouts, setPayouts] = useState<Payout[]>(seedPayouts);
  const [personas, setPersonas] = useState<Persona[]>(seedPersonas);
  const [generations, setGenerations] =
    useState<Generation[]>(seedGenerations);
  const [hydrated, setHydrated] = useState(false);

  useEffect(() => {
    let mounted = true;
    AsyncStorage.getItem(STORAGE_KEY)
      .then((raw) => {
        if (!mounted || !raw) return;
        try {
          const data = JSON.parse(raw) as Partial<PersistShape>;
          if (data.profile) setProfile(data.profile);
          if (data.links) setLinks(data.links);
          if (data.transactions) setTransactions(data.transactions);
          if (data.payouts) setPayouts(data.payouts);
          if (data.personas) setPersonas(data.personas);
          if (data.generations) setGenerations(data.generations);
        } catch {
          // ignore corrupt cache
        }
      })
      .finally(() => {
        if (mounted) setHydrated(true);
      });
    return () => {
      mounted = false;
    };
  }, []);

  useEffect(() => {
    if (!hydrated) return;
    const payload: PersistShape = {
      profile,
      links,
      transactions,
      payouts,
      personas,
      generations,
    };
    AsyncStorage.setItem(STORAGE_KEY, JSON.stringify(payload)).catch(() => {});
  }, [hydrated, profile, links, transactions, payouts, personas, generations]);

  const convertLink = useCallback<AppState["convertLink"]>(
    (url, subId, productTitle) => {
      const merchant = detectMerchant(url);
      const code = shortCode();
      const sub = subId?.trim() || `${profile.subId}_${Math.floor(Math.random() * 99)}`;
      const link: AffiliateLink = {
        id: genId("lnk"),
        originalUrl: url,
        shortCode: `edg.gn/${code}`,
        profitUrl: `https://edg.gn/${code}?aff=${profile.subId}&sub=${sub}`,
        merchant,
        productTitle: productTitle?.trim() || `${merchant} product`,
        category: "Apparel",
        createdAt: Date.now(),
        clicks: 0,
        conversions: 0,
        earnings: 0,
        estCommissionPct: commissionForMerchant(merchant),
      };
      setLinks((prev) => [link, ...prev]);
      return link;
    },
    [profile.subId],
  );

  const requestPayout = useCallback<AppState["requestPayout"]>(
    (amount, method, account) => {
      const payout: Payout = {
        id: genId("po"),
        amount,
        method,
        account,
        status: "processing",
        idempotencyKey: `ik_${genId("k").slice(2, 14)}`,
        createdAt: Date.now(),
      };
      setPayouts((prev) => [payout, ...prev]);
      // Simulate completion after a short delay (background UX cue)
      setTimeout(() => {
        setPayouts((prev) =>
          prev.map((p) =>
            p.id === payout.id ? { ...p, status: "completed" } : p,
          ),
        );
      }, 3500);
      return payout;
    },
    [],
  );

  const addPersona = useCallback<AppState["addPersona"]>((name, imageCount) => {
    const persona: Persona = {
      id: genId("psn"),
      name,
      baseModel: "FLUX.1",
      sampleImage: require("../assets/images/model4.png"),
      status: "training",
      trainingProgress: 0.05,
      imageCount,
    };
    setPersonas((prev) => [persona, ...prev]);
    let progress = 0.05;
    const interval = setInterval(() => {
      progress += 0.12;
      if (progress >= 1) {
        clearInterval(interval);
        setPersonas((prev) =>
          prev.map((p) =>
            p.id === persona.id
              ? {
                  ...p,
                  status: "ready",
                  trainingProgress: 1,
                  trainedAt: Date.now(),
                }
              : p,
          ),
        );
      } else {
        setPersonas((prev) =>
          prev.map((p) =>
            p.id === persona.id ? { ...p, trainingProgress: progress } : p,
          ),
        );
      }
    }, 900);
    return persona;
  }, []);

  const addGeneration = useCallback<AppState["addGeneration"]>((g) => {
    const item: Generation = {
      id: genId("g"),
      createdAt: Date.now(),
      ...g,
    };
    setGenerations((prev) => [item, ...prev].slice(0, 24));
    return item;
  }, []);

  const setKycStatus = useCallback<AppState["setKycStatus"]>((status) => {
    setProfile((p) => ({ ...p, kycStatus: status }));
  }, []);

  const totals = useMemo(() => {
    const sumBy = (s: Transaction["status"]) =>
      transactions
        .filter((t) => t.status === s)
        .reduce((acc, t) => acc + t.amount, 0);
    const pending = sumBy("pending");
    const confirmed = sumBy("confirmed");
    const due = sumBy("due");
    const paid = sumBy("paid");
    return {
      pending,
      confirmed,
      due,
      paid,
      available: confirmed + due,
    };
  }, [transactions]);

  const value = useMemo<AppState>(
    () => ({
      profile,
      links,
      transactions,
      payouts,
      personas,
      generations,
      totals,
      convertLink,
      requestPayout,
      addPersona,
      addGeneration,
      setKycStatus,
    }),
    [
      profile,
      links,
      transactions,
      payouts,
      personas,
      generations,
      totals,
      convertLink,
      requestPayout,
      addPersona,
      addGeneration,
      setKycStatus,
    ],
  );

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

export function useApp(): AppState {
  const ctx = useContext(AppContext);
  if (!ctx) throw new Error("useApp must be used within AppProvider");
  return ctx;
}
