"use client";

import {
  createContext,
  useCallback,
  useContext,
  useEffect,
  useMemo,
  useState,
  type ReactNode,
} from "react";
import { DEMO_BOOKING_REFS } from "@/lib/mocks/guestData";

const STORAGE_SESSION = "shitaye_session_v1";
const STORAGE_ORDERS = "shitaye_orders_v1";

export type OrderCategory = "room-service" | "laundry" | "gym" | "spa";

export type OrderRecord = {
  id: string;
  category: OrderCategory;
  title: string;
  detail: string;
  totalUsd: number;
  placedAt: string;
  status: "pending" | "confirmed" | "completed";
};

export type MemberSession = {
  kind: "member";
  email: string;
  displayName: string;
  points: number;
  tier: "Gold" | "Silver";
  /** How they signed in — for display only */
  authMethod: "otp" | "password" | "google" | "apple" | "facebook";
};

export type BookingRefSession = {
  kind: "bookingRef";
  bookingRef: string;
  guestName: string;
  roomLabel: string;
  checkOut: string;
};

export type GuestSession = MemberSession | BookingRefSession;

type AuthContextValue = {
  session: GuestSession | null;
  orders: OrderRecord[];
  isHydrated: boolean;
  /** Demo OTP is always 123456 */
  requestOtp: (email: string) => Promise<{ ok: boolean; message: string }>;
  verifyOtp: (email: string, code: string) => Promise<{ ok: boolean; message: string }>;
  loginPassword: (email: string, password: string) => Promise<{ ok: boolean; message: string }>;
  loginSocial: (provider: "google" | "apple" | "facebook") => void;
  loginBookingRef: (ref: string) => { ok: boolean; message: string };
  logout: () => void;
  addOrder: (o: Omit<OrderRecord, "id" | "placedAt" | "status"> & { status?: OrderRecord["status"] }) => void;
  awardPoints: (points: number) => void;
};

const AuthContext = createContext<AuthContextValue | null>(null);

function loadOrders(): OrderRecord[] {
  if (typeof window === "undefined") return [];
  try {
    const raw = localStorage.getItem(STORAGE_ORDERS);
    if (!raw) return seedOrders();
    const parsed = JSON.parse(raw) as OrderRecord[];
    return Array.isArray(parsed) ? parsed : seedOrders();
  } catch {
    return seedOrders();
  }
}

function seedOrders(): OrderRecord[] {
  return [
    {
      id: "seed-rs-1",
      category: "room-service",
      title: "Room service · American breakfast ×2",
      detail: "Delivered 07:15 · Room charge",
      totalUsd: 36,
      placedAt: new Date(Date.now() - 86400000 * 2).toISOString(),
      status: "completed",
    },
    {
      id: "seed-l-1",
      category: "laundry",
      title: "Laundry · Express + 3 shirts",
      detail: "Returned same evening",
      totalUsd: 27,
      placedAt: new Date(Date.now() - 86400000).toISOString(),
      status: "completed",
    },
    {
      id: "seed-sp-1",
      category: "spa",
      title: "Spa · Signature Swedish 60 min",
      detail: "Apr 4 · 15:00",
      totalUsd: 85,
      placedAt: new Date(Date.now() - 86400000 * 3).toISOString(),
      status: "confirmed",
    },
  ];
}

function loadSession(): GuestSession | null {
  if (typeof window === "undefined") return null;
  try {
    const raw = localStorage.getItem(STORAGE_SESSION);
    if (!raw) return null;
    return JSON.parse(raw) as GuestSession;
  } catch {
    return null;
  }
}

function persistSession(s: GuestSession | null) {
  if (typeof window === "undefined") return;
  if (s) localStorage.setItem(STORAGE_SESSION, JSON.stringify(s));
  else localStorage.removeItem(STORAGE_SESSION);
}

function persistOrders(orders: OrderRecord[]) {
  if (typeof window === "undefined") return;
  localStorage.setItem(STORAGE_ORDERS, JSON.stringify(orders));
}

export function AuthProvider({ children }: { children: ReactNode }) {
  const [session, setSession] = useState<GuestSession | null>(null);
  const [orders, setOrders] = useState<OrderRecord[]>([]);
  const [isHydrated, setIsHydrated] = useState(false);

  useEffect(() => {
    setSession(loadSession());
    setOrders(loadOrders());
    setIsHydrated(true);
  }, []);

  const requestOtp = useCallback(async (email: string) => {
    if (!/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(email)) {
      return { ok: false, message: "Enter a valid email address." };
    }
    return { ok: true, message: "Demo code sent. Use OTP 123456 to continue." };
  }, []);

  const verifyOtp = useCallback(async (email: string, code: string) => {
    const trimmed = code.replace(/\s/g, "");
    if (trimmed !== "123456") {
      return { ok: false, message: "Invalid code. Demo OTP is 123456." };
    }
    const local = email.split("@")[0] ?? "Guest";
    const name = local.charAt(0).toUpperCase() + local.slice(1);
    const next: MemberSession = {
      kind: "member",
      email: email.toLowerCase(),
      displayName: name,
      points: 2400,
      tier: "Gold",
      authMethod: "otp",
    };
    setSession(next);
    persistSession(next);
    return { ok: true, message: "Signed in." };
  }, []);

  const loginPassword = useCallback(async (email: string, password: string) => {
    if (!email || !password) {
      return { ok: false, message: "Email and password required." };
    }
    if (password !== "shitaye" && password !== "demo123") {
      return {
        ok: false,
        message: "Incorrect password. Try demo password: shitaye",
      };
    }
    const local = email.split("@")[0] ?? "Guest";
    const name = local.charAt(0).toUpperCase() + local.slice(1);
    const next: MemberSession = {
      kind: "member",
      email: email.toLowerCase(),
      displayName: name,
      points: 2400,
      tier: "Gold",
      authMethod: "password",
    };
    setSession(next);
    persistSession(next);
    return { ok: true, message: "Signed in." };
  }, []);

  const loginSocial = useCallback((provider: "google" | "apple" | "facebook") => {
    const names: Record<typeof provider, string> = {
      google: "Google Guest",
      apple: "Apple Guest",
      facebook: "Facebook Guest",
    };
    const next: MemberSession = {
      kind: "member",
      email: `guest.${provider}@shitaye.demo`,
      displayName: names[provider],
      points: 2100,
      tier: "Silver",
      authMethod: provider,
    };
    setSession(next);
    persistSession(next);
  }, []);

  const loginBookingRef = useCallback((ref: string) => {
    const key = ref.trim().toUpperCase();
    const row = DEMO_BOOKING_REFS[key];
    if (!row) {
      return {
        ok: false,
        message: "Reference not found. Try SHITAYE-2026-DEMO or GUEST-1234.",
      };
    }
    const next: BookingRefSession = {
      kind: "bookingRef",
      bookingRef: key,
      guestName: row.guestName,
      roomLabel: row.room,
      checkOut: row.checkOut,
    };
    setSession(next);
    persistSession(next);
    return { ok: true, message: "Linked to your stay." };
  }, []);

  const logout = useCallback(() => {
    setSession(null);
    persistSession(null);
  }, []);

  const addOrder = useCallback(
    (
      o: Omit<OrderRecord, "id" | "placedAt" | "status"> & {
        status?: OrderRecord["status"];
      },
    ) => {
      const rec: OrderRecord = {
        ...o,
        id: `ord-${Date.now()}-${Math.random().toString(36).slice(2, 7)}`,
        placedAt: new Date().toISOString(),
        status: o.status ?? "pending",
      };
      setOrders((prev) => {
        const next = [rec, ...prev];
        persistOrders(next);
        return next;
      });
      if (session?.kind === "member") {
        const bonus = Math.min(150, Math.round(o.totalUsd * 2));
        setSession((s) => {
          if (!s || s.kind !== "member") return s;
          const u = { ...s, points: s.points + bonus };
          persistSession(u);
          return u;
        });
      }
    },
    [session],
  );

  const awardPoints = useCallback((points: number) => {
    setSession((s) => {
      if (!s || s.kind !== "member") return s;
      const u = { ...s, points: s.points + points };
      persistSession(u);
      return u;
    });
  }, []);

  const value = useMemo<AuthContextValue>(
    () => ({
      session,
      orders,
      isHydrated,
      requestOtp,
      verifyOtp,
      loginPassword,
      loginSocial,
      loginBookingRef,
      logout,
      addOrder,
      awardPoints,
    }),
    [
      session,
      orders,
      isHydrated,
      requestOtp,
      verifyOtp,
      loginPassword,
      loginSocial,
      loginBookingRef,
      logout,
      addOrder,
      awardPoints,
    ],
  );

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

export function useAuth() {
  const ctx = useContext(AuthContext);
  if (!ctx) throw new Error("useAuth must be used within AuthProvider");
  return ctx;
}
