/**
 * @file AppContext.tsx
 * @description Contexto global principal ("State Manager") da aplicação. 
 * Efetua a ligação direta e centralizada com a base de dados Supabase 
 * lidando com Auth, Consultas (Shops/Services) e CRUD (Criar/Ler/Atualizar/Apagar).
 */
import React, { createContext, useContext, useEffect, useMemo, useState } from 'react';
import { Appointment, Barber, BarberShop, CartItem, Order, Product, Service, User, WaitlistEntry, AppNotification } from '../types';
import { supabase } from '../lib/supabase';
import { storage } from '../lib/storage';
import * as Device from 'expo-device';
import Constants from 'expo-constants';
import { Platform } from 'react-native';

type State = {
  user?: User;
  shops: BarberShop[];
  shopsReady: boolean;
  cart: CartItem[];
  favorites: string[];
  appointments: Appointment[];
  orders: Order[];
  waitlists: WaitlistEntry[];
  notifications: AppNotification[];
};

type AppContextValue = State & {
  login: (email: string, password: string) => Promise<User | undefined>;
  logout: () => Promise<void>;
  register: (payload: any) => Promise<User | undefined>;
  toggleFavorite: (shopId: string) => void;
  isFavorite: (shopId: string) => boolean;
  addToCart: (item: CartItem) => void;
  removeFromCart: (refId: string) => void;
  placeOrder: (customerId: string, shopId: string) => Promise<Order | null>;
  clearCart: () => void;
  createAppointment: (input: Omit<Appointment, 'id' | 'status' | 'total'>) => Promise<Appointment | null>;
  updateAppointmentStatus: (id: string, status: Appointment['status']) => Promise<void>;
  updateOrderStatus: (id: string, status: Order['status']) => Promise<void>;
  addService: (shopId: string, service: Omit<Service, 'id'>) => Promise<void>;
  updateService: (shopId: string, service: Service) => Promise<void>;
  deleteService: (shopId: string, serviceId: string) => Promise<void>;
  addProduct: (shopId: string, product: Omit<Product, 'id'>) => Promise<void>;
  updateProduct: (shopId: string, product: Product) => Promise<void>;
  deleteProduct: (shopId: string, productId: string) => Promise<void>;
  addBarber: (shopId: string, barber: Omit<Barber, 'id'>) => Promise<void>;
  updateBarber: (shopId: string, barber: Barber) => Promise<void>;
  deleteBarber: (shopId: string, barberId: string) => Promise<void>;
  updateShopDetails: (shopId: string, payload: Partial<BarberShop>) => Promise<void>;
  submitReview: (shopId: string, appointmentId: string, rating: number, comment: string) => Promise<void>;
  joinWaitlist: (shopId: string, serviceId: string, barberId: string, date: string) => Promise<boolean>;
  markNotificationRead: (id: string) => Promise<void>;
  refreshShops: () => Promise<void>;
};

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

export const AppProvider = ({ children }: { children: React.ReactNode }) => {
  const [shops, setShops] = useState<BarberShop[]>([]);
  const [appointments, setAppointments] = useState<Appointment[]>([]);
  const [orders, setOrders] = useState<Order[]>([]);
  const [cart, setCart] = useState<CartItem[]>([]);
  const [favorites, setFavorites] = useState<string[]>([]);
  const [waitlists, setWaitlists] = useState<WaitlistEntry[]>([]);
  const [notifications, setNotifications] = useState<AppNotification[]>([]);
  const [user, setUser] = useState<User | undefined>(undefined);
  const [shopsReady, setShopsReady] = useState(false);
  const [loading, setLoading] = useState(true);

  useEffect(() => {
    let mounted = true;
    if (user?.id) {
      storage.get<{ favorites?: string[]; cart?: CartItem[] }>(`smart-agenda-user-${user.id}`, {}).then((stored) => {
        if (!mounted) return;
        setFavorites(Array.isArray(stored.favorites) ? stored.favorites : []);
      });
    } else {
      setFavorites([]);
    }
    return () => {
      mounted = false;
    };
  }, [user?.id]);

  useEffect(() => {
    if (user?.id) {
      storage.set(`smart-agenda-user-${user.id}`, { favorites, cart });
    }
  }, [favorites, cart, user?.id]);

  const applySupabaseUser = async (authUser: any): Promise<User | undefined> => {
    if (!authUser) return undefined;

    const { data: prof, error: profErr } = await supabase
      .from('profiles')
      .select('shop_id, role, name, fcm_token, shop_name')
      .eq('id', authUser.id)
      .single();

    const role = (prof?.role as any) || authUser.user_metadata?.role || 'cliente';
    const shopId = prof?.shop_id || (role === 'barbearia' ? authUser.id : undefined);

    const nextUser: User = {
      id: authUser.id,
      name: prof?.name || authUser.user_metadata?.name || authUser.email?.split('@')[0] || 'Utilizador',
      email: authUser.email || '',
      password: '',
      role,
      shopId,
      fcmToken: prof?.fcm_token || undefined,
    };

    // If it's a barber and the shop record doesn't exist, create it (matching web logic)
    if (role === 'barbearia' && shopId) {
      const { data: existingShop } = await supabase.from('shops').select('id').eq('id', shopId).single();
      if (!existingShop) {
        const shopName = prof?.shop_name || authUser.user_metadata?.shopName || `Barbearia de ${nextUser.name}`;
        await supabase.from('shops').insert([{
          id: shopId,
          name: shopName,
          address: 'Endereço a definir',
          rating: 0,
        }]);
      }
    }

    setUser(nextUser);

    registerForPushNotificationsAsync().then((token) => {
      if (token && token !== prof?.fcm_token) {
        supabase.from('profiles').update({ fcm_token: token }).eq('id', authUser.id).then();
      }
    });

    return nextUser;
  };

  useEffect(() => {
    const loadUser = async () => {
      const { data } = await supabase.auth.getUser();
      if (data.user) await applySupabaseUser(data.user);
    };
    loadUser();
  }, []);

  const refreshShops = async () => {
    console.log('AppContext: refreshShops iniciado');
    try {
      const { data: shopsData } = await supabase.from('shops').select('*');
      const { data: servicesData } = await supabase.from('services').select('*');
      const { data: barbersData } = await supabase.from('barbers').select('*');
      const { data: productsData } = await supabase.from('products').select('*');
      const { data: appointmentsData } = await supabase.from('appointments').select('*');
      const { data: ordersData } = await supabase.from('orders').select('*');
      const { data: waitlistsData } = await supabase.from('waitlist').select('*');
      const { data: notificationsData } = await supabase.from('notifications').select('*');
      const { data: reviewsData } = await supabase.from('reviews').select('shop_id, rating');

      if (shopsData) {
        const merged: BarberShop[] = shopsData.map((shop: any) => {
          const shopReviews = (reviewsData || []).filter((r: any) => r.shop_id === shop.id);
          const avgRating = shopReviews.length
            ? shopReviews.reduce((sum: number, r: any) => sum + (r.rating || 0), 0) / shopReviews.length
            : shop.rating || 0;

          return {
            id: shop.id,
            name: shop.name,
            address: shop.address || '',
            rating: avgRating,
            imageUrl: shop.image_url || shop.imageUrl || undefined,
            schedule: shop.schedule || undefined,
            paymentMethods: shop.payment_methods || undefined,
            socialNetworks: shop.social_networks || undefined,
            contacts: shop.contacts || undefined,
            services: (servicesData || []).filter((s: any) => s.shop_id === shop.id).map((s: any) => ({
              id: s.id,
              name: s.name,
              price: s.price || 0,
              duration: s.duration || 30,
              barberIds: s.barber_ids || [],
            })),
            products: (productsData || []).filter((p: any) => p.shop_id === shop.id).map((p: any) => ({
              id: p.id,
              name: p.name,
              price: p.price || 0,
              stock: p.stock || 0,
            })),
            barbers: (barbersData || []).filter((b: any) => b.shop_id === shop.id).map((b: any) => ({
              id: b.id,
              name: b.name,
              imageUrl: b.image_url || undefined,
              specialties: b.specialties || [],
              schedule: b.schedule || [],
            })),
          };
        });
        setShops(merged);
      }

      if (appointmentsData) {
        setAppointments(
          appointmentsData.map((a: any) => ({
            id: a.id,
            shopId: a.shop_id,
            serviceId: a.service_id,
            barberId: a.barber_id,
            customerId: a.customer_id,
            date: a.date,
            status: a.status as Appointment['status'],
            total: a.total,
          }))
        );
      }

      if (ordersData) {
        setOrders(
          ordersData.map((o: any) => ({
            id: o.id,
            shopId: o.shop_id,
            customerId: o.customer_id,
            items: o.items,
            total: o.total,
            status: o.status as Order['status'],
            createdAt: o.created_at,
          }))
        );
      }

      if (waitlistsData) {
        setWaitlists(
          waitlistsData.map((w: any) => ({
            id: w.id,
            shopId: w.shop_id,
            serviceId: w.service_id,
            barberId: w.barber_id,
            customerId: w.customer_id,
            date: w.date,
            status: w.status as WaitlistEntry['status'],
            createdAt: w.created_at,
          }))
        );
      }

      if (notificationsData) {
        setNotifications(
          notificationsData.map((n: any) => ({
            id: n.id,
            userId: n.user_id,
            message: n.message,
            read: n.read,
            createdAt: n.created_at,
          }))
        );
      }
      setShopsReady(true);
    } catch (err) {
      console.error('Error refreshing shops:', err);
      setShopsReady(true);
    }
  };

  useEffect(() => {
    console.log('AppContext: Iniciando carregamento...');
    const init = async () => {
      try {
        await refreshShops();
        console.log('AppContext: Lojas carregadas com sucesso.');
      } catch (e) {
        console.error('AppContext: Erro no init:', e);
      } finally {
        setLoading(false);
        console.log('AppContext: setLoading(false)');
      }
    };
    init();
  }, []);

  const login = async (email: string, password: string) => {
    const { data, error } = await supabase.auth.signInWithPassword({ email, password });
    if (error || !data.user) {
      console.error('Erro no login:', error);
      return undefined;
    }

    const nextUser = await applySupabaseUser(data.user);
    await refreshShops();
    return nextUser;
  };

  const logout = async () => {
    await supabase.auth.signOut();
    setUser(undefined);
  };

  const register = async (payload: any) => {
    const { name, email, password, role, shopName } = payload;
    const { data, error } = await supabase.auth.signUp({
      email,
      password,
      options: {
        data: {
          name,
          role,
          shopName: role === 'barbearia' ? shopName : null,
          shop_name: role === 'barbearia' ? shopName : null,
        },
      },
    });

    if (error) throw error;
    if (!data.user) throw new Error('Erro ao criar conta');

    if (!data.session) return undefined;
    const nextUser = await applySupabaseUser(data.user);
    await refreshShops();
    return nextUser;
  };

  const toggleFavorite = (shopId: string) => {
    setFavorites((prev) =>
      prev.includes(shopId) ? prev.filter((id) => id !== shopId) : [...prev, shopId]
    );
  };

  const isFavorite = (shopId: string) => favorites.includes(shopId);

  const removeFromCart = (refId: string) => {
    setCart((prev) => prev.filter((i) => i.refId !== refId));
  };

  const placeOrder = async (customerId: string, shopId: string) => {
    const shopItems = cart.filter((i) => i.shopId === shopId);
    if (!shopItems.length) return null;

    const shop = shops.find((s) => s.id === shopId);
    const total = shopItems.reduce((sum, i) => {
      const price =
        i.type === 'service'
          ? shop?.services.find((s) => s.id === i.refId)?.price ?? 0
          : shop?.products.find((p) => p.id === i.refId)?.price ?? 0;
      return sum + price * i.qty;
    }, 0);

    const { data, error } = await supabase.from('orders').insert([{
      shop_id: shopId,
      customer_id: customerId,
      items: shopItems,
      total,
      status: 'pendente',
    }]).select().single();

    if (error || !data) {
      console.error('Erro ao criar pedido:', error);
      return null;
    }

    const newOrder: Order = {
      id: data.id,
      shopId: data.shop_id,
      customerId: data.customer_id,
      items: data.items,
      total: data.total,
      status: data.status as Order['status'],
      createdAt: data.created_at,
    };

    await refreshShops();
    setCart((prev) => prev.filter((i) => i.shopId !== shopId));
    return newOrder;
  };

  const addToCart = (item: CartItem) => {
    setCart((prev: CartItem[]) => {
      const next = [...prev];
      const existing = next.find((i) => i.shopId === item.shopId && i.type === item.type && i.refId === item.refId);
      if (existing) existing.qty += item.qty;
      else next.push(item);
      return next;
    });
  };

  const clearCart = () => setCart([]);

  const addService = async (shopId: string, service: Omit<Service, 'id'>) => {
    const { error } = await supabase.from('services').insert([{
      shop_id: shopId,
      name: service.name,
      price: service.price,
      duration: service.duration,
      barber_ids: service.barberIds || [],
    }]);
    if (error) {
      console.error('Erro addService:', error);
      throw error;
    }
    await refreshShops();
  };

  const updateService = async (shopId: string, service: Service) => {
    await supabase.from('services').update({
      name: service.name,
      price: service.price,
      duration: service.duration,
      barber_ids: service.barberIds || [],
    }).eq('id', service.id);
    await refreshShops();
  };

  const deleteService = async (shopId: string, serviceId: string) => {
    await supabase.from('services').delete().eq('id', serviceId);
    await refreshShops();
  };

  const addProduct = async (shopId: string, product: Omit<Product, 'id'>) => {
    const { error } = await supabase.from('products').insert([{ 
      shop_id: shopId, 
      name: product.name,
      price: product.price,
      stock: product.stock
    }]);
    if (error) {
      console.error('Erro addProduct:', error);
      throw error;
    }
    await refreshShops();
  };

  const updateProduct = async (shopId: string, product: Product) => {
    const { id, ...data } = product;
    await supabase.from('products').update(data).eq('id', id);
    await refreshShops();
  };

  const deleteProduct = async (shopId: string, productId: string) => {
    await supabase.from('products').delete().eq('id', productId);
    await refreshShops();
  };

  const addBarber = async (shopId: string, barber: Omit<Barber, 'id'>) => {
    const { error } = await supabase.from('barbers').insert([{
      shop_id: shopId,
      name: barber.name,
      specialties: barber.specialties,
      schedule: barber.schedule || [],
      image_url: barber.imageUrl,
    }]);
    if (error) {
      console.error('Erro addBarber:', error);
      throw error;
    }
    await refreshShops();
  };

  const updateBarber = async (shopId: string, barber: Barber) => {
    await supabase.from('barbers').update({
      name: barber.name,
      specialties: barber.specialties,
      schedule: barber.schedule,
      image_url: barber.imageUrl,
    }).eq('id', barber.id);
    await refreshShops();
  };

  const deleteBarber = async (shopId: string, barberId: string) => {
    await supabase.from('barbers').delete().eq('id', barberId);
    await refreshShops();
  };

  const updateShopDetails = async (shopId: string, payload: Partial<BarberShop>) => {
    const { services, products, barbers, id, imageUrl, paymentMethods, socialNetworks, contacts, schedule, ...rest } = payload;
    const updateData: Record<string, any> = { ...rest };
    
    if (imageUrl !== undefined) updateData.image_url = imageUrl;
    if (paymentMethods !== undefined) updateData.payment_methods = paymentMethods;
    if (socialNetworks !== undefined) updateData.social_networks = socialNetworks;
    if (contacts !== undefined) updateData.contacts = contacts;
    if (schedule !== undefined) updateData.schedule = schedule;

    const { error } = await supabase.from('shops').update(updateData).eq('id', shopId);
    if (error) {
      console.error('Erro updateShopDetails:', error);
      throw error;
    }

    if (payload.name) {
      await supabase.from('profiles').update({ shop_name: payload.name }).eq('shop_id', shopId);
    }

    await refreshShops();
  };

  const submitReview = async (shopId: string, appointmentId: string, rating: number, comment: string) => {
    const { data } = await supabase.auth.getUser();
    const customerId = data.user?.id;
    if (!customerId) throw new Error('Sessão expirada. Faz login novamente.');

    const { error } = await supabase.from('reviews').insert([{
      shop_id: shopId,
      customer_id: customerId,
      appointment_id: appointmentId,
      rating,
      comment: comment.trim() || null,
    }]);
    if (error) throw error;
    await refreshShops();
  };

  const createAppointment = async (input: Omit<Appointment, 'id' | 'status' | 'total'>) => {
    const svc = shops.flatMap(s => s.services).find(s => s.id === input.serviceId);
    const total = svc ? svc.price : 0;
    const { data } = await supabase.from('appointments').insert([{ 
      shop_id: input.shopId, 
      service_id: input.serviceId,
      barber_id: input.barberId,
      customer_id: input.customerId,
      date: input.date,
      status: 'pendente',
      total,
      reminder_minutes: input.reminderMinutes
    }]).select().single();
    await refreshShops();
    return data as any as Appointment;
  };

  const updateAppointmentStatus = async (id: string, status: Appointment['status']) => {
    const apt = appointments.find((a) => a.id === id);
    await supabase.from('appointments').update({ status }).eq('id', id);

    if (status === 'cancelado' && apt) {
      const waitlistDate = apt.date.split(' ')[0]; // Extract YYYY-MM-DD
      const waitingUsers = waitlists.filter(w => w.barberId === apt.barberId && w.date === waitlistDate && w.status === 'pending');
      
      if (waitingUsers.length > 0) {
        const notificationsToInsert = waitingUsers.map(w => ({
          user_id: w.customerId,
          message: `Surgiu uma vaga no horário que pretendia a ${waitlistDate} às ${apt.date.split(' ')[1]}! Corra para fazer a reserva.`
        }));
        
        await supabase.from('notifications').insert(notificationsToInsert);
        
        const waitlistIds = waitingUsers.map(w => w.id);
        await supabase.from('waitlist').update({ status: 'notified' }).in('id', waitlistIds);
      }
    }

    await refreshShops();
  };

  const updateOrderStatus = async (id: string, status: Order['status']) => {
    await supabase.from('orders').update({ status }).eq('id', id);
    await refreshShops();
  };

  const joinWaitlist = async (shopId: string, serviceId: string, barberId: string, date: string) => {
    if (!user) return false;
    const { error } = await supabase.from('waitlist').insert([{
      shop_id: shopId,
      service_id: serviceId,
      barber_id: barberId,
      customer_id: user.id,
      date,
      status: 'pending'
    }]);
    if (error) {
      console.error('Erro ao entrar na lista de espera:', error);
      return false;
    }
    await refreshShops();
    return true;
  };

  const markNotificationRead = async (id: string) => {
    const { error } = await supabase.from('notifications').update({ read: true }).eq('id', id);
    if (error) console.error("Erro ao marcar notificação:", error);
    else await refreshShops();
  };

  const value: AppContextValue = useMemo(
    () => ({
      user,
      shops,
      shopsReady,
      cart,
      favorites,
      appointments,
      orders,
      waitlists,
      notifications,
      login,
      logout,
      register,
      toggleFavorite,
      isFavorite,
      addToCart,
      removeFromCart,
      placeOrder,
      clearCart,
      createAppointment,
      updateAppointmentStatus,
      updateOrderStatus,
      addService,
      updateService,
      deleteService,
      addProduct,
      updateProduct,
      deleteProduct,
      addBarber,
      updateBarber,
      deleteBarber,
      updateShopDetails,
      submitReview,
      joinWaitlist,
      markNotificationRead,
      refreshShops,
    }),
    [user, shops, shopsReady, cart, favorites, appointments, orders, waitlists, notifications]
  );

  if (loading) return null;

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

export const useApp = () => {
  const ctx = useContext(AppContext);
  if (!ctx) throw new Error('useApp deve ser usado dentro de AppProvider');
  return ctx;
};

async function registerForPushNotificationsAsync() {
  let token;
  if (Platform.OS === 'android' && Constants.appOwnership === 'expo') {
    console.log('Push remoto Android requer development build; ignorado no Expo Go.');
    return;
  }

  const Notifications = await import('expo-notifications');

  if (Platform.OS === 'android') {
    await Notifications.setNotificationChannelAsync('default', {
      name: 'default',
      importance: Notifications.AndroidImportance.MAX,
      vibrationPattern: [0, 250, 250, 250],
      lightColor: '#FF231F7C',
    });
  }

  if (Device.isDevice) {
    const { status: existingStatus } = await Notifications.getPermissionsAsync();
    let finalStatus = existingStatus;
    if (existingStatus !== 'granted') {
      const { status } = await Notifications.requestPermissionsAsync();
      finalStatus = status;
    }
    if (finalStatus !== 'granted') {
      console.log('Falha ao obter token push!');
      return;
    }
    token = (await Notifications.getExpoPushTokenAsync({
      projectId: 'b018a5db-c940-4364-81ee-596ced75cae3',
    })).data;
  } else {
    console.log('Necessário dispositivo físico para notificações push');
  }

  return token;
}
