import {
  deleteAccount,
  getAllAccounts,
  updateAccountInfo,
  type LocalAccount,
} from "@/repository/account";
import type { UserProfile } from "@/types";
import { create } from "zustand";
import { useDbStore } from "./db";
import { fetchProfileApi } from "@/api/profile";

export interface IAuthState {
  profile: UserProfile | null;
  authenticating: boolean;
  activeAccount: LocalAccount | null;
  loadingAccounts: boolean;
  accounts: LocalAccount[];
  signInRequired: boolean;

  hasAuthenticated: boolean;
  hasLoadedAccounts: boolean;

  loadAccounts: () => Promise<void>;
  updateActiveAccount: (account: LocalAccount) => Promise<void>;
  deleteActiveAccount: () => Promise<void>;

  authenticate: () => Promise<void>;

  requireSignIn: () => void;
  signOut: () => void;
}

const getActiveAccountId = (): string | null => {
  const accountId = localStorage.getItem("guard-selected");
  return accountId;
};

const saveActiveAccountId = (accountId: string): void => {
  localStorage.setItem("guard-selected", accountId);
};

const resetActiveAccount = (): void => {
  localStorage.removeItem("guard-selected");
};

// TODO: maybe add deleteActiveAccount

export const useAuth = create<IAuthState>((set, get) => ({
  profile: null,
  authenticating: false,
  activeAccount: null,
  accounts: [],
  loadingAccounts: false,
  signInRequired: false,

  hasAuthenticated: false,
  hasLoadedAccounts: false,

  updateActiveAccount: async (account) => {
    set({ activeAccount: account });

    saveActiveAccountId(account.accountId);

    set({ signInRequired: false });
  },

  loadAccounts: async () => {
    set({ loadingAccounts: true });

    const db = useDbStore.getState().db;
    if (!db) return;

    const accounts = await getAllAccounts(db);

    if (!accounts || accounts.length === 0) {
      set({ signInRequired: true });
    }

    const active = getActiveAccountId();

    if (!active) {
      set({ signInRequired: true });
    } else {
      const account = accounts.find((acc) => acc.accountId === active);

      if (!account) {
        resetActiveAccount();
        set({ signInRequired: true });
      } else {
        set({ activeAccount: account });
      }
    }

    set({
      accounts,
      loadingAccounts: false,
      hasLoadedAccounts: true,
    });
  },

  deleteActiveAccount: async () => {
    resetActiveAccount();
    set({ activeAccount: null });
    get().loadAccounts();
  },

  authenticate: async () => {
    const { authenticating } = get();
    if (authenticating) return;

    set({ authenticating: true });

    try {
      const response = await fetchProfileApi();

      try {
        // update local account information
        const db = useDbStore.getState().db;
        if (db) {
          await updateAccountInfo(db, {
            accountId: response.id,
            label: response.full_name,
            ...(response.profile_picture
              ? { profilePicture: response.profile_picture }
              : {}),
          });
        }
      } finally {
        set({ profile: response });
      }
    } catch (err) {
      // TODO: set error
      console.log(err);
    } finally {
      set({ authenticating: false, hasAuthenticated: true });
    }
  },

  requireSignIn: () => set({ signInRequired: true }),

  signOut: async () => {
    resetActiveAccount();

    const db = useDbStore.getState().db;
    const activeAccount = get().activeAccount;
    if (db && activeAccount) {
      await deleteAccount(db, activeAccount.accountId);
    }

    await get().loadAccounts();

    set({ activeAccount: null, signInRequired: true });
  },
}));
