import { create } from 'zustand';
import { API_URL, CUSTOMER_EMAIL, CUSTOMER_PASSWORD } from '../runtime-config';

export type CustomerProfile = {
  fullName: string;
  email: string;
  phone: string;
};

export type CustomerAddress = {
  label: string;
  street: string;
  number: string;
  complement: string;
  neighborhood: string;
  city: string;
  state: string;
  zipCode: string;
};

type LoginResponse = {
  accessToken: string;
};

interface CustomerSessionState {
  token?: string;
  initialized: boolean;
  loading: boolean;
  saving: boolean;
  error: string;
  profile: CustomerProfile;
  address: CustomerAddress;
  bootstrap: () => Promise<void>;
  clearError: () => void;
  saveProfile: (payload: { fullName: string }) => Promise<void>;
  saveAddress: (payload: CustomerAddress) => Promise<void>;
}

const defaultProfile: CustomerProfile = {
  fullName: 'Camila Cliente',
  email: 'cliente@chego.app',
  phone: '5511966665555',
};

const defaultAddress: CustomerAddress = {
  label: 'Casa',
  street: '',
  number: '',
  complement: '',
  neighborhood: '',
  city: '',
  state: '',
  zipCode: '',
};

function toMessage(error: unknown) {
  if (error instanceof Error) {
    return error.message;
  }

  return 'Falha ao sincronizar os dados da conta.';
}

async function requestJson<T>(path: string, init?: RequestInit) {
  const response = await fetch(`${API_URL}${path}`, {
    ...init,
    headers: {
      'Content-Type': 'application/json',
      ...(init?.headers ?? {}),
    },
  });

  if (!response.ok) {
    const text = await response.text();
    throw new Error(text || `Falha ao acessar ${path}.`);
  }

  return response.json() as Promise<T>;
}

export const useCustomerSession = create<CustomerSessionState>((set, get) => ({
  token: undefined,
  initialized: false,
  loading: false,
  saving: false,
  error: '',
  profile: defaultProfile,
  address: defaultAddress,
  bootstrap: async () => {
    if (get().loading) {
      return;
    }

    set({ loading: true, error: '' });
    try {
      let token = get().token;

      if (!token) {
        const login = await requestJson<LoginResponse>('/auth/login/customer', {
          method: 'POST',
          body: JSON.stringify({ email: CUSTOMER_EMAIL, password: CUSTOMER_PASSWORD }),
        });
        token = login.accessToken;
      }

      const headers = { Authorization: `Bearer ${token}` };
      const [profile, address] = await Promise.all([
        requestJson<CustomerProfile>('/customer/me', { headers }),
        requestJson<CustomerAddress>('/customer/me/address', { headers }),
      ]);

      set({
        token,
        profile: {
          fullName: profile.fullName,
          email: profile.email,
          phone: profile.phone,
        },
        address: {
          label: address.label,
          street: address.street,
          number: address.number,
          complement: address.complement,
          neighborhood: address.neighborhood,
          city: address.city,
          state: address.state,
          zipCode: address.zipCode,
        },
        initialized: true,
        loading: false,
      });
    } catch (error) {
      set({ error: toMessage(error), initialized: true, loading: false });
    }
  },
  clearError: () => set({ error: '' }),
  saveProfile: async ({ fullName }) => {
    const { token } = get();
    if (!token) {
      throw new Error('Sessao do cliente nao iniciada.');
    }

    set({ saving: true, error: '' });
    try {
      const profile = await requestJson<CustomerProfile>('/customer/me', {
        method: 'PATCH',
        headers: { Authorization: `Bearer ${token}` },
        body: JSON.stringify({ fullName }),
      });

      set({
        profile: {
          fullName: profile.fullName,
          email: profile.email,
          phone: profile.phone,
        },
        saving: false,
      });
    } catch (error) {
      set({ error: toMessage(error), saving: false });
      throw error;
    }
  },
  saveAddress: async (payload) => {
    const { token } = get();
    if (!token) {
      throw new Error('Sessao do cliente nao iniciada.');
    }

    set({ saving: true, error: '' });
    try {
      const address = await requestJson<CustomerAddress>('/customer/me/address', {
        method: 'PATCH',
        headers: { Authorization: `Bearer ${token}` },
        body: JSON.stringify(payload),
      });

      set({
        address: {
          label: address.label,
          street: address.street,
          number: address.number,
          complement: address.complement,
          neighborhood: address.neighborhood,
          city: address.city,
          state: address.state,
          zipCode: address.zipCode,
        },
        saving: false,
      });
    } catch (error) {
      set({ error: toMessage(error), saving: false });
      throw error;
    }
  },
}));
