import { api } from "@/services/api";
import type { ProfileTypeValue } from "@/services/companies.service";
import { companiesService } from "@/services/companies.service";
import type {
  LoginPayload,
  LoginResponse,
  OtpResponse,
  SignupPayload,
  SignupResponse,
} from "@/types/auth";
import type { Result } from "@/utils/result";
import { extractApiError } from "@/utils/result";
import { useQuery, useQueryClient } from "@tanstack/react-query";

function setCookie(name: string, value: string, days: number) {
  const expires = new Date();
  expires.setDate(expires.getDate() + days);
  document.cookie = `${name}=${value}; path=/; expires=${expires.toUTCString()}; SameSite=Lax`;
}

function getCookie(name: string): string | undefined {
  return document.cookie
    .split("; ")
    .find((row) => row.startsWith(`${name}=`))
    ?.split("=")[1];
}

const useAuth = () => {
  const queryClient = useQueryClient();
  const hasToken = !!getCookie("auth-token");

  const authQuery = useQuery(
    api.auth.getMyInfo.queryOptions({
      enabled: hasToken,
      retry: false,
      refetchOnMount: false,
      refetchOnReconnect: false,
      staleTime: 10 * 60 * 1000,
      refetchOnWindowFocus: false,
    }),
  );

  const companyQuery = useQuery(
    api.companies.getInfo.queryOptions({
      enabled: !!authQuery.data?.id,
      retry: false,
      staleTime: 10 * 60 * 1000,
      refetchOnWindowFocus: false,
    }),
  );

  const isPending = authQuery.isPending && hasToken;
  const isAuthenticated = hasToken && !!authQuery.data && !authQuery.isError;

  const login = async (
    payload: LoginPayload,
  ): Promise<Result<LoginResponse>> => {
    try {
      const res = await api.auth.login.call(payload);
      setCookie("auth-token", res.token, 7);
      setCookie("refresh-token", res.refreshToken, 7);
      await authQuery.refetch();
      return { success: true, data: res };
    } catch (err) {
      return { success: false, error: extractApiError(err) };
    }
  };

  const signup = async (
    payload: SignupPayload,
  ): Promise<Result<SignupResponse>> => {
    try {
      const res = await api.auth.createUser.call(payload);
      setCookie("auth-token", res.token, 7);
      setCookie("refresh-token", res.refreshToken, 7);
      await authQuery.refetch();
      const otpCode = res.otp?.split(" ")?.[6] ?? "";
      localStorage.setItem("otp", otpCode);
      localStorage.setItem("otp-phone", payload.phoneNumber);
      localStorage.setItem("otp-email", payload.email);
      api.auth.sendOTP
        .call({ phone: payload.phoneNumber, otp: otpCode })
        .catch(() => { });
      return { success: true, data: res };
    } catch (err) {
      return { success: false, error: extractApiError(err) };
    }
  };

  const setPassword = async (data: {
    newPassword: string;
    confirmPassword: string;
  }): Promise<Result<void>> => {
    try {
      const userId = authQuery.data?.id ?? "";
      const email = localStorage.getItem("otp-email") ?? "";
      const verificationCode = localStorage.getItem("otp") ?? "";
      await api.auth.setPassword.call({
        newPassword: data.newPassword,
        confirmPassword: data.confirmPassword,
        userId,
        email,
        verificationCode,
      });
      ["userId", "otp", "otp-phone", "otp-email"].forEach((k) =>
        localStorage.removeItem(k),
      );
      await queryClient.invalidateQueries({
        queryKey: api.auth.getMyInfo.queryKey(),
      });
      return { success: true, data: undefined };
    } catch (err) {
      return { success: false, error: extractApiError(err) };
    }
  };

  const verifyOTP = async (otp: string): Promise<Result<OtpResponse>> => {
    try {
      const phone = localStorage.getItem("otp-phone") ?? "";
      const res = await api.auth.verifyOTP.call({ phone, otp });
      return { success: true, data: res };
    } catch (err) {
      return { success: false, error: extractApiError(err) };
    }
  };

  const sendOTP = async (otp: string): Promise<Result<OtpResponse>> => {
    try {
      const phone = localStorage.getItem("otp-phone") ?? "";
      const res = await api.auth.sendOTP.call({ phone, otp });
      return { success: true, data: res };
    } catch (err) {
      return { success: false, error: extractApiError(err) };
    }
  };

  const generateVerificationCode = async (
    type: string,
  ): Promise<Result<string>> => {
    try {
      const email = localStorage.getItem("otp-email") ?? "";
      const phoneNumber = localStorage.getItem("otp-phone") ?? "";
      const res = await api.auth.generateVerificationCode.call({
        email,
        phoneNumber,
        type,
      });
      return { success: true, data: res };
    } catch (err) {
      return { success: false, error: extractApiError(err) };
    }
  };

  // Active-mode (importer/exporter) state, sourced from the persisted profile.
  const companyInfo = isAuthenticated ? (companyQuery.data ?? null) : null;
  const activeProfileType = companyInfo?.profile?.activeProfileType ?? null;
  const activeCompanyProfileId =
    companyInfo?.profile?.activeCompanyProfileId ?? null;
  const companyType = companyInfo?.company?.type ?? null;
  const companyStatus = companyInfo?.company?.status ?? null;
  // A company can create bookings only once an admin has approved it (active).
  const isCompanyApproved = companyStatus === "active";
  const onboardingCompleted =
    companyInfo?.profile?.onboardingCompleted ?? false;
  const onboardingStep = companyInfo?.profile?.onboardingStep ?? null;

  /** Refetch everything scoped to the active operational profile. */
  const invalidateScopedData = async () => {
    await Promise.all([
      queryClient.invalidateQueries({
        queryKey: api.companies.getInfo.queryKey(),
      }),
      queryClient.invalidateQueries({
        queryKey: api.companies.getDashboard.queryKey(),
      }),
      queryClient.invalidateQueries({ queryKey: ["bookings"] }),
    ]);
  };

  const switchMode = async (
    type: ProfileTypeValue,
  ): Promise<Result<void>> => {
    try {
      await api.companies.setActiveMode.call({ type });
      await invalidateScopedData();
      return { success: true, data: undefined };
    } catch (err) {
      return { success: false, error: extractApiError(err) };
    }
  };

  const createProfileAndSwitch = async (
    type: ProfileTypeValue,
    licenseFiles: File[],
  ): Promise<Result<void>> => {
    try {
      const created = await api.companies.createCompanyProfile.call({ type });
      if (licenseFiles.length > 0) {
        await companiesService.uploadProfileLicense(created.id, licenseFiles);
      }
      await invalidateScopedData();
      return { success: true, data: undefined };
    } catch (err) {
      return { success: false, error: extractApiError(err) };
    }
  };

  const logout = async () => {
    try {
      await api.auth.logout.call();
    } catch {
      // proceed with client-side cleanup even if server call fails
    }
    [
      "auth-token",
      "refresh-token",
      "auth-user",
      "current-position-id",
      "selected-position-id",
    ].forEach((name) => {
      document.cookie = `${name}=; Max-Age=0; path=/`;
    });
    localStorage.clear();
    queryClient.clear();
  };

  return {
    isPending,
    isAuthenticated,
    user: isAuthenticated ? (authQuery.data ?? null) : null,
    company: isAuthenticated ? (companyQuery.data ?? null) : null,
    customer: isAuthenticated ? (companyQuery.data ?? null) : null,
    activeProfileType,
    activeCompanyProfileId,
    companyType,
    companyStatus,
    isCompanyApproved,
    onboardingCompleted,
    onboardingStep,
    switchMode,
    createProfileAndSwitch,
    login,
    signup,
    setPassword,
    verifyOTP,
    sendOTP,
    generateVerificationCode,
    logout,
    authQuery,
    companyQuery,
    customerQuery: companyQuery,
  };
};

export default useAuth;
