"use client";

import {
  useCallback,
  useEffect,
  useState,
} from "react";

import {
  getMyOrganization,
  updateMyOrganization,
  uploadMyOrganizationLogo,
  uploadMySystemLogo,
} from "../service/my-organization-service";

import type {
  MyOrganizationProfile,
  UpdateMyOrganizationPayload,
} from "../types/my-organization-types";

function getErrorMessage(
  error: unknown,
): string {
  if (
    error instanceof Error &&
    error.message.trim()
  ) {
    return error.message;
  }

  if (
    typeof error === "string" &&
    error.trim()
  ) {
    return error;
  }

  return "Unable to load organization.";
}

export function useMyOrganization() {
  const [
    profile,
    setProfile,
  ] =
    useState<MyOrganizationProfile | null>(
      null,
    );

  /*
   * Initial value is true.
   *
   * Therefore we do NOT need:
   * setIsLoading(true)
   * inside the initial useEffect.
   */
  const [
    isLoading,
    setIsLoading,
  ] = useState(true);

  const [
    isSaving,
    setIsSaving,
  ] = useState(false);

  const [
    isUploadingLogo,
    setIsUploadingLogo,
  ] = useState(false);

  const [
    isUploadingSystemLogo,
    setIsUploadingSystemLogo,
  ] = useState(false);

  const [
    error,
    setError,
  ] = useState<string | null>(
    null,
  );

  // ============================================================
  // INITIAL LOAD
  //
  // IMPORTANT:
  // Do not call synchronous setState at the start of this effect.
  // State is updated only after the async request resolves.
  // ============================================================

  useEffect(() => {
    let cancelled = false;

    async function loadInitialOrganization(): Promise<void> {
      try {
        const result =
          await getMyOrganization();

        if (cancelled) {
          return;
        }

        setProfile(
          result,
        );

        setError(
          null,
        );
      } catch (
        caughtError: unknown
      ) {
        if (cancelled) {
          return;
        }

        setProfile(
          null,
        );

        setError(
          getErrorMessage(
            caughtError,
          ),
        );
      } finally {
        if (!cancelled) {
          setIsLoading(
            false,
          );
        }
      }
    }

    void loadInitialOrganization();

    return () => {
      cancelled = true;
    };
  }, []);

  // ============================================================
  // REFRESH
  //
  // This is triggered by a user action, so setState here is fine.
  // ============================================================

  const refetch =
    useCallback(
      async (): Promise<void> => {
        try {
          setIsLoading(
            true,
          );

          setError(
            null,
          );

          const result =
            await getMyOrganization();

          setProfile(
            result,
          );
        } catch (
          caughtError: unknown
        ) {
          setProfile(
            null,
          );

          setError(
            getErrorMessage(
              caughtError,
            ),
          );
        } finally {
          setIsLoading(
            false,
          );
        }
      },
      [],
    );

  // ============================================================
  // UPDATE ORGANIZATION INFORMATION
  // ============================================================

  const updateOrganization =
    useCallback(
      async (
        payload:
          UpdateMyOrganizationPayload,
      ): Promise<MyOrganizationProfile | null> => {
        try {
          setIsSaving(
            true,
          );

          setError(
            null,
          );

          const result =
            await updateMyOrganization(
              payload,
            );

          setProfile(
            result,
          );

          return result;
        } catch (
          caughtError: unknown
        ) {
          setError(
            getErrorMessage(
              caughtError,
            ),
          );

          return null;
        } finally {
          setIsSaving(
            false,
          );
        }
      },
      [],
    );

  // ============================================================
  // UPLOAD ORGANIZATION LOGO
  // ============================================================

  const uploadOrganizationLogo =
    useCallback(
      async (
        file: File,
      ): Promise<MyOrganizationProfile | null> => {
        try {
          setIsUploadingLogo(
            true,
          );

          setError(
            null,
          );

          const result =
            await uploadMyOrganizationLogo(
              file,
            );

          setProfile(
            result,
          );

          return result;
        } catch (
          caughtError: unknown
        ) {
          setError(
            getErrorMessage(
              caughtError,
            ),
          );

          return null;
        } finally {
          setIsUploadingLogo(
            false,
          );
        }
      },
      [],
    );

  // ============================================================
  // UPLOAD SYSTEM LOGO
  // ============================================================

  const uploadSystemLogo =
    useCallback(
      async (
        file: File,
      ): Promise<MyOrganizationProfile | null> => {
        try {
          setIsUploadingSystemLogo(
            true,
          );

          setError(
            null,
          );

          const result =
            await uploadMySystemLogo(
              file,
            );

          setProfile(
            result,
          );

          return result;
        } catch (
          caughtError: unknown
        ) {
          setError(
            getErrorMessage(
              caughtError,
            ),
          );

          return null;
        } finally {
          setIsUploadingSystemLogo(
            false,
          );
        }
      },
      [],
    );

  return {
    profile,

    isLoading,
    isSaving,

    isUploadingLogo,
    isUploadingSystemLogo,

    error,

    refetch,

    updateOrganization,

    uploadOrganizationLogo,
    uploadSystemLogo,
  };
}