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

const API_BASE_URL = (
  process.env.NEXT_PUBLIC_API_URL ??
  "http://localhost:3001/api/v1"
).replace(/\/+$/, "");

const API_ORIGIN = (() => {
  try {
    return new URL(
      API_BASE_URL,
    ).origin;
  } catch {
    return "http://localhost:3001";
  }
})();

async function parseErrorMessage(
  response: Response,
): Promise<string> {
  try {
    const result =
      (await response.json()) as {
        message?:
          | string
          | string[];

        error?: string;
      };

    if (
      Array.isArray(
        result.message,
      )
    ) {
      return result.message.join(
        ", ",
      );
    }

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

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

    return `Request failed with status ${response.status}.`;
  } catch {
    return `Request failed with status ${response.status}.`;
  }
}

function unwrapApiData<T>(
  result:
    | ApiResponse<T>
    | T,
): T {
  if (
    typeof result ===
      "object" &&
    result !== null &&
    "data" in result
  ) {
    return (
      result as ApiResponse<T>
    ).data;
  }

  return result as T;
}

/*
 * Backend returns paths like:
 *
 * /uploads/stakeholders/abc.png
 * /uploads/system-logos/abc.png
 *
 * Browser needs:
 *
 * http://localhost:3001/uploads/...
 */
export function resolveMyOrganizationAssetUrl(
  value:
    | string
    | null
    | undefined,
): string {
  const path =
    String(
      value ?? "",
    ).trim();

  if (!path) {
    return "";
  }

  if (
    path.startsWith(
      "http://",
    ) ||
    path.startsWith(
      "https://",
    ) ||
    path.startsWith(
      "blob:",
    ) ||
    path.startsWith(
      "data:",
    )
  ) {
    return path;
  }

  if (
    path.startsWith("/")
  ) {
    return `${API_ORIGIN}${path}`;
  }

  return `${API_ORIGIN}/${path}`;
}

// ============================================================
// GET MY ORGANIZATION
// ============================================================

export async function getMyOrganization(): Promise<MyOrganizationProfile> {
  const response =
    await fetch(
      `${API_BASE_URL}/my-organization`,
      {
        method: "GET",

        headers: {
          Accept:
            "application/json",
        },

        credentials:
          "include",

        cache:
          "no-store",
      },
    );

  if (!response.ok) {
    throw new Error(
      await parseErrorMessage(
        response,
      ),
    );
  }

  const result =
    (await response.json()) as
      | ApiResponse<MyOrganizationProfile>
      | MyOrganizationProfile;

  return unwrapApiData(
    result,
  );
}

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

export async function updateMyOrganization(
  payload: UpdateMyOrganizationPayload,
): Promise<MyOrganizationProfile> {
  const response =
    await fetch(
      `${API_BASE_URL}/my-organization`,
      {
        method: "PATCH",

        headers: {
          Accept:
            "application/json",

          "Content-Type":
            "application/json",
        },

        credentials:
          "include",

        body:
          JSON.stringify(
            payload,
          ),
      },
    );

  if (!response.ok) {
    throw new Error(
      await parseErrorMessage(
        response,
      ),
    );
  }

  const result =
    (await response.json()) as
      | ApiResponse<MyOrganizationProfile>
      | MyOrganizationProfile;

  return unwrapApiData(
    result,
  );
}

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

export async function uploadMyOrganizationLogo(
  file: File,
): Promise<MyOrganizationProfile> {
  const formData =
    new FormData();

  formData.append(
    "logo",
    file,
    file.name,
  );

  const response =
    await fetch(
      `${API_BASE_URL}/my-organization/logo`,
      {
        method: "PATCH",

        headers: {
          Accept:
            "application/json",
        },

        credentials:
          "include",

        body:
          formData,
      },
    );

  if (!response.ok) {
    throw new Error(
      await parseErrorMessage(
        response,
      ),
    );
  }

  const result =
    (await response.json()) as
      | ApiResponse<MyOrganizationProfile>
      | MyOrganizationProfile;

  return unwrapApiData(
    result,
  );
}

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

export async function uploadMySystemLogo(
  file: File,
): Promise<MyOrganizationProfile> {
  const formData =
    new FormData();

  /*
   * Must match backend:
   * FileInterceptor("systemLogo")
   */
  formData.append(
    "systemLogo",
    file,
    file.name,
  );

  const response =
    await fetch(
      `${API_BASE_URL}/my-organization/system-logo`,
      {
        method: "PATCH",

        headers: {
          Accept:
            "application/json",
        },

        credentials:
          "include",

        body:
          formData,
      },
    );

  if (!response.ok) {
    throw new Error(
      await parseErrorMessage(
        response,
      ),
    );
  }

  const result =
    (await response.json()) as
      | ApiResponse<MyOrganizationProfile>
      | MyOrganizationProfile;

  return unwrapApiData(
    result,
  );
}