import React, { createContext, useContext, useState, useEffect, useRef } from 'react';
import { Alert, AppState } from 'react-native';
import AsyncStorage from '@react-native-async-storage/async-storage';
import { setApiAuth, clearApiAuth } from '../services/api';
import { API_URL } from '../constants/defaults';

const AuthContext = createContext(null);

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

export function AuthProvider({ children }) {
  // ── Auth / onboarding state ──────────────────────────────────────
  const [appScreen, setAppScreen] = useState('loading'); // 'loading' | 'onboarding' | 'app'
  const appScreenRef = useRef('loading');
  const [onboardStep, setOnboardStep] = useState('launch'); // 'launch'|'login'|'setup_company'|'setup_account'|'setup_ecom'|'setup_shipping'
  const [currentUser, setCurrentUser] = useState(null); // { id, name, role, can_pick, can_pack, can_print }
  const [authToken, setAuthToken] = useState(null);
  const tokenRef = useRef(null);
  const [authCompany, setAuthCompany] = useState(null);
  const authCompanyRef = useRef(null);
  const [obLogin, setObLogin] = useState({ company: '', password: '', role: 'user', saveMe: true });
  const [obSetup, setObSetup] = useState({
    businessSlug: '', clientKey: '',
    companyName: '', companySlug: '',
    displayName: '', username: '', password: '', confirmPassword: '',
    ecomProvider: 'none', ecomStoreUrl: '', ecomApiKey: '',
    shipProvider: 'packie', shipUsername: '', shipApiKey: '',
    senderName: '', senderStreet: '', senderCity: '', senderPostcode: '',
  });
  const [obLoading, setObLoading] = useState(false);
  const [obError, setObError] = useState('');
  const [staffName, setStaffName] = useState('');
  const [showLogin, setShowLogin] = useState(false);
  const [tempName, setTempName] = useState('');
  const [securityMode, setSecurityMode] = useState('individual_pin');
  const [sessionExpiresAt, setSessionExpiresAt] = useState(null);

  const appStateRef = useRef(AppState.currentState);

  const isExpired = (expiresAt) => {
    if (!expiresAt) return false;
    const normalized = String(expiresAt).includes('T') ? expiresAt : `${expiresAt.replace(' ', 'T')}Z`;
    const expiresMs = Date.parse(normalized);
    return Number.isFinite(expiresMs) && expiresMs <= Date.now();
  };

  // ── Derived values ──────────────────────────────────────────────
  const isMasterUser = currentUser?.role === 'master';
  const isSecondaryUser = currentUser?.role === 'secondary';
  const effectiveCanPick = !!currentUser?.can_pick;
  const effectiveCanPack = !!currentUser?.can_pack;
  const effectiveCanPrint = !!currentUser?.can_print;

  // ── Keep api module in sync whenever auth changes ───────────────
  useEffect(() => {
    if (authToken && authCompany) {
      setApiAuth(authToken, authCompany);
    }
  }, [authToken, authCompany]);

  // ── Session expiry handler ─────────────────────────────────────
  const handleSessionExpired = async () => {
    await AsyncStorage.removeItem('authSession');
    tokenRef.current = null;
    authCompanyRef.current = null;
    appScreenRef.current = 'onboarding';
    clearApiAuth();
    setAuthToken(null);
    setAuthCompany(null);
    setCurrentUser(null);
    setSessionExpiresAt(null);
    setShowLogin(false);
    setAppScreen('onboarding');
    setOnboardStep('login');
  };

  const applyAuthSession = async ({ token, user, company, expires_at }) => {
    const resolvedCompany = company || authCompanyRef.current || authCompany;
    if (!token || !resolvedCompany || !user) return false;

    await AsyncStorage.setItem('authSession', JSON.stringify({
      token,
      user,
      company: resolvedCompany,
      expires_at,
      security_mode: securityMode,
    }));

    tokenRef.current = token;
    authCompanyRef.current = resolvedCompany;
    appScreenRef.current = 'app';
    setApiAuth(token, resolvedCompany);
    setAuthToken(token);
    setAuthCompany(resolvedCompany);
    setCurrentUser(user);
    setSessionExpiresAt(expires_at || null);
    setStaffName(user.name || '');
    setTempName(user.name || '');
    setAppScreen('app');
    return true;
  };

  // ── Onboarding: login to existing company ───────────────────────
  const handleObLogin = async (overrideCompany, overridePassword, overrideRole) => {
    const company  = overrideCompany  ?? obLogin.company.trim().toLowerCase();
    const password = overridePassword ?? obLogin.password;
    const role = overrideRole ?? obLogin.role ?? 'user';
    if (!company || !password) {
      setObError('Company and password are required.');
      return false;
    }
    setObLoading(true);
    setObError('');
    try {
      const res = await fetch(API_URL, {
        method: 'POST',
        headers: { 'Content-Type': 'application/json', 'X-Requested-With': 'AfrihairApp' },
        body: JSON.stringify({
          action: 'login',
          company,
          password,
          role,
          device_name: 'Warehouse App',
          remember: !!obLogin.saveMe || !!overrideCompany,
        }),
      });
      const text = await res.text();
      let data;
      try {
        data = JSON.parse(text);
      } catch (_err) {
        console.log('Login: non-JSON response', res.status, text);
        setObError('Connection error. Check your internet and try again.');
        setObLoading(false);
        return false;
      }
      if (!data.success) {
        setObError(data.error || 'Login failed. Check your credentials.');
        setObLoading(false);
        return false;
      }
      const nextSecurityMode = ['master_only', 'shared_honor', 'individual_pin'].includes(data.security_mode)
        ? data.security_mode
        : securityMode;
      const session = { token: data.token, user: data.user, company, expires_at: data.expires_at, security_mode: nextSecurityMode };
      await AsyncStorage.setItem('authSession', JSON.stringify(session));
      if (obLogin.saveMe || overrideCompany) {
        await AsyncStorage.setItem('savedCredentials', JSON.stringify({ company, role }));
      } else {
        await AsyncStorage.removeItem('savedCredentials');
      }
      // Set refs synchronously so downstream code can use them immediately
      tokenRef.current = data.token;
      authCompanyRef.current = company;
      appScreenRef.current = 'app';
      // Keep api module in sync
      setApiAuth(data.token, company);
      // React state updates
      setAuthToken(data.token);
      setAuthCompany(company);
      setCurrentUser(data.user);
      setSecurityMode(nextSecurityMode);
      setSessionExpiresAt(data.expires_at || null);
      setStaffName(data.user.name);
      setTempName(data.user.name);
      setAppScreen('app');
      setShowLogin(data.user?.role !== 'master' && nextSecurityMode !== 'master_only');
      setObLoading(false);
      return true;
    } catch (_e) {
      setObError('Connection error. Check your internet and try again.');
      setObLoading(false);
      return false;
    }
  };

  // ── Onboarding: verify against master registry ──────────────────
  const handleVerifyClient = async () => {
    const slug = obSetup.businessSlug.trim().toLowerCase().replace(/[^a-z0-9\-_]/g, '');
    const key  = obSetup.clientKey.trim();
    if (!slug || !key) return setObError('Business slug and setup key are required.');
    setObLoading(true);
    setObError('');
    try {
      const res = await fetch(API_URL, {
        method: 'POST',
        headers: { 'Content-Type': 'application/json', 'X-Requested-With': 'AfrihairApp' },
        body: JSON.stringify({ action: 'verify_client', business_slug: slug, client_key: key }),
      });
      const data = await res.json();
      if (!data.valid) {
        setObError(data.error || 'Invalid business slug or setup key.');
        setObLoading(false);
        return;
      }
      setObSetup(prev => ({
        ...prev,
        companyName: data.business_name || prev.companyName,
        companySlug: slug,
      }));
      setObError('');
      setOnboardStep('setup_company');
    } catch (_e) {
      setObError('Connection error. Check your internet and try again.');
    }
    setObLoading(false);
  };

  // ── Onboarding: first-time setup wizard ─────────────────────────
  const handleObSetup = async () => {
    const s = obSetup;
    const slug = s.companySlug.trim().toLowerCase().replace(/[^a-z0-9\-_]/g, '');
    if (!s.companyName.trim() || !slug) return setObError('Company name and ID are required.');
    if (!s.username.trim() || s.password.length < 8) return setObError('Username required. Password must be at least 8 characters.');
    if (s.password !== s.confirmPassword) return setObError('Passwords do not match.');
    if (s.ecomProvider !== 'none' && (!s.ecomStoreUrl.trim() || !s.ecomApiKey.trim())) return setObError('Ecommerce store URL and API key are required.');
    if (!s.shipUsername.trim() || !s.shipApiKey.trim()) return setObError('Shipping credentials are required.');
    if (!s.senderStreet.trim() || !s.senderCity.trim() || !s.senderPostcode.trim()) return setObError('Sender address (street, city, postcode) is required.');

    setObLoading(true);
    setObError('');
    try {
      const res = await fetch(API_URL, {
        method: 'POST',
        headers: { 'Content-Type': 'application/json', 'X-Requested-With': 'AfrihairApp' },
        body: JSON.stringify({
          action: 'run_setup',
          business_slug: s.businessSlug.trim(),
          company_name: s.companyName.trim(),
          company_slug: slug,
          display_name: s.displayName.trim() || s.username.trim(),
          username: s.username.trim(),
          password: s.password,
          ecom_provider: s.ecomProvider,
          ecom_store_url: s.ecomStoreUrl.trim(),
          ecom_api_key: s.ecomApiKey.trim(),
          shipping_provider: s.shipProvider,
          shipping_username: s.shipUsername.trim(),
          shipping_api_key: s.shipApiKey.trim(),
          sender_name: s.senderName.trim(),
          sender_street: s.senderStreet.trim(),
          sender_city: s.senderCity.trim(),
          sender_postcode: s.senderPostcode.trim(),
        }),
      });
      const data = await res.json();
      if (!data.success) {
        setObError(data.error || 'Setup failed. Please try again.');
        setObLoading(false);
        return;
      }
      // Auto-login with master credentials
      const ok = await handleObLogin(slug, s.password, 'admin');
      if (!ok) {
        setObError('Setup complete! Please log in manually.');
        setOnboardStep('login');
        setObLogin(prev => ({ ...prev, company: slug, role: 'admin', password: '' }));
      }
    } catch (_e) {
      setObError('Connection error. Check your internet and try again.');
      setObLoading(false);
    }
  };

  // ── Staff selection (dismisses login prompt) ────────────────────
  const selectStaff = async (staff) => {
    const staffObj = typeof staff === 'object' && staff ? staff : null;
    const name = staffObj?.name || String(staff || '');
    if (!name.trim()) return Alert.alert('Required', 'Please select a name.');

    if (securityMode === 'shared_honor' && staffObj?.id) {
      try {
        const res = await fetch(API_URL, {
          method: 'POST',
          headers: {
            'Content-Type': 'application/json',
            'X-Requested-With': 'AfrihairApp',
            ...(tokenRef.current ? { 'X-Auth-Token': tokenRef.current } : {}),
            ...(authCompanyRef.current ? { 'X-Company': authCompanyRef.current } : {}),
          },
          body: JSON.stringify({
            action: 'switch_staff_honor',
            staff_id: staffObj.id,
            device_name: 'Warehouse App',
          }),
        });
        const data = await res.json();
        if (!data.success) {
          Alert.alert('Switch User', data.error || 'Could not switch user.');
          return;
        }
        await applyAuthSession(data);
      } catch (_e) {
        Alert.alert('Switch User', 'Could not reach server.');
        return;
      }
    } else {
      const trimmed = name.trim();
      await AsyncStorage.setItem('staffName', trimmed);
      setStaffName(trimmed);
      setTempName(trimmed);
    }

    setShowLogin(false);
  };

  // ── Init useEffect: check AsyncStorage for existing session ─────
  useEffect(() => {
    const init = async () => {
      const sessionJson = await AsyncStorage.getItem('authSession');
      if (sessionJson) {
        try {
          const session = JSON.parse(sessionJson);
          if (!session.company) {
            // Legacy sessions (before multi-DB routing) must be re-authenticated.
            await AsyncStorage.removeItem('authSession');
          } else if (session.user?.role === 'master' && isExpired(session.expires_at)) {
            await AsyncStorage.removeItem('authSession');
          } else {
            // Trust stored session; server will 401 on expiry (handled by AppContext)
            tokenRef.current = session.token;
            authCompanyRef.current = session.company;
            appScreenRef.current = 'app';
            setApiAuth(session.token, session.company);
            setAuthToken(session.token);
            setAuthCompany(session.company);
            setCurrentUser(session.user || null);
            setSessionExpiresAt(session.expires_at || null);
            if (['master_only', 'shared_honor', 'individual_pin'].includes(session.security_mode)) {
              setSecurityMode(session.security_mode);
            }
            setStaffName(session.user?.name || '');
            setTempName(session.user?.name || '');
            setAppScreen('app');
            return;
          }
        } catch (_) { await AsyncStorage.removeItem('authSession'); }
      }

      // No valid session -- show onboarding
      const savedCreds = await AsyncStorage.getItem('savedCredentials');
      if (savedCreds) {
        try {
          const creds = JSON.parse(savedCreds);
          setObLogin(prev => ({ ...prev, company: creds.company || '', role: creds.role || 'user', saveMe: true }));
        } catch (_) {}
      }
      appScreenRef.current = 'onboarding';
      setAppScreen('onboarding');
      setOnboardStep('launch');
    };
    init();
  }, []);

  // ── AppState useEffect: on foreground resume, show login prompt based on security mode ──
  useEffect(() => {
    const subscription = AppState.addEventListener('change', nextAppState => {
      if (appStateRef.current.match(/inactive|background/) && nextAppState === 'active') {
        if (currentUser?.role === 'master') {
          if (isExpired(sessionExpiresAt)) {
            handleSessionExpired();
          }
          appStateRef.current = nextAppState;
          return;
        }
        // Only show worker prompt if security mode requires it
        if (securityMode === 'individual_pin' || securityMode === 'shared_honor') {
          setShowLogin(true);
        }
      }
      appStateRef.current = nextAppState;
    });
    return () => subscription.remove();
  }, [currentUser?.role, securityMode, sessionExpiresAt]);

  useEffect(() => {
    if (securityMode === 'master_only' || currentUser?.role === 'master') {
      setShowLogin(false);
    }
  }, [currentUser?.role, securityMode]);

  useEffect(() => {
    if (currentUser?.role !== 'master' || !sessionExpiresAt) return undefined;
    const normalized = String(sessionExpiresAt).includes('T') ? sessionExpiresAt : `${sessionExpiresAt.replace(' ', 'T')}Z`;
    const expiresMs = Date.parse(normalized);
    if (!Number.isFinite(expiresMs)) return undefined;
    const timeout = setTimeout(() => {
      handleSessionExpired();
    }, Math.max(0, expiresMs - Date.now()));
    return () => clearTimeout(timeout);
  }, [currentUser?.role, sessionExpiresAt]);

  // ── Context value ───────────────────────────────────────────────
  const value = {
    // State
    appScreen, setAppScreen,
    onboardStep, setOnboardStep,
    currentUser, setCurrentUser,
    authToken, setAuthToken,
    authCompany, setAuthCompany,
    obLogin, setObLogin,
    obSetup, setObSetup,
    obLoading, setObLoading,
    obError, setObError,
    staffName, setStaffName,
    showLogin, setShowLogin,
    tempName, setTempName,
    securityMode, setSecurityMode,
    // Refs
    appScreenRef,
    tokenRef,
    authCompanyRef,
    // Derived
    isMasterUser,
    isSecondaryUser,
    effectiveCanPick,
    effectiveCanPack,
    effectiveCanPrint,
    // Functions
    handleSessionExpired,
    handleObLogin,
    handleVerifyClient,
    handleObSetup,
    applyAuthSession,
    selectStaff,
  };

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