/**
 * Copyright (c) 2023-present Plane Software, Inc. and contributors
 * SPDX-License-Identifier: AGPL-3.0-only
 * See the LICENSE file for details.
 */

import type { EFileAssetType } from "@plane/types";
import { getFileURL } from "@plane/utils";

import CoverImage1 from "@/app/assets/cover-images/image_1.jpg?url";
import CoverImage10 from "@/app/assets/cover-images/image_10.jpg?url";
import CoverImage11 from "@/app/assets/cover-images/image_11.jpg?url";
import CoverImage12 from "@/app/assets/cover-images/image_12.jpg?url";
import CoverImage13 from "@/app/assets/cover-images/image_13.jpg?url";
import CoverImage14 from "@/app/assets/cover-images/image_14.jpg?url";
import CoverImage15 from "@/app/assets/cover-images/image_15.jpg?url";
import CoverImage16 from "@/app/assets/cover-images/image_16.jpg?url";
import CoverImage17 from "@/app/assets/cover-images/image_17.jpg?url";
import CoverImage18 from "@/app/assets/cover-images/image_18.jpg?url";
import CoverImage19 from "@/app/assets/cover-images/image_19.jpg?url";
import CoverImage2 from "@/app/assets/cover-images/image_2.jpg?url";
import CoverImage20 from "@/app/assets/cover-images/image_20.jpg?url";
import CoverImage21 from "@/app/assets/cover-images/image_21.jpg?url";
import CoverImage22 from "@/app/assets/cover-images/image_22.jpg?url";
import CoverImage23 from "@/app/assets/cover-images/image_23.jpg?url";
import CoverImage24 from "@/app/assets/cover-images/image_24.jpg?url";
import CoverImage25 from "@/app/assets/cover-images/image_25.jpg?url";
import CoverImage26 from "@/app/assets/cover-images/image_26.jpg?url";
import CoverImage27 from "@/app/assets/cover-images/image_27.jpg?url";
import CoverImage28 from "@/app/assets/cover-images/image_28.jpg?url";
import CoverImage29 from "@/app/assets/cover-images/image_29.jpg?url";
import CoverImage3 from "@/app/assets/cover-images/image_3.jpg?url";
import CoverImage4 from "@/app/assets/cover-images/image_4.jpg?url";
import CoverImage5 from "@/app/assets/cover-images/image_5.jpg?url";
import CoverImage6 from "@/app/assets/cover-images/image_6.jpg?url";
import CoverImage7 from "@/app/assets/cover-images/image_7.jpg?url";
import CoverImage8 from "@/app/assets/cover-images/image_8.jpg?url";
import CoverImage9 from "@/app/assets/cover-images/image_9.jpg?url";

import { FileService } from "@/services/file.service";

const fileService = new FileService();

/**
 * Map of all available static cover images
 * These are pre-loaded images available in the assets/cover-images folder
 */
export const STATIC_COVER_IMAGES = {
  IMAGE_1: CoverImage1,
  IMAGE_2: CoverImage2,
  IMAGE_3: CoverImage3,
  IMAGE_4: CoverImage4,
  IMAGE_5: CoverImage5,
  IMAGE_6: CoverImage6,
  IMAGE_7: CoverImage7,
  IMAGE_8: CoverImage8,
  IMAGE_9: CoverImage9,
  IMAGE_10: CoverImage10,
  IMAGE_11: CoverImage11,
  IMAGE_12: CoverImage12,
  IMAGE_13: CoverImage13,
  IMAGE_14: CoverImage14,
  IMAGE_15: CoverImage15,
  IMAGE_16: CoverImage16,
  IMAGE_17: CoverImage17,
  IMAGE_18: CoverImage18,
  IMAGE_19: CoverImage19,
  IMAGE_20: CoverImage20,
  IMAGE_21: CoverImage21,
  IMAGE_22: CoverImage22,
  IMAGE_23: CoverImage23,
  IMAGE_24: CoverImage24,
  IMAGE_25: CoverImage25,
  IMAGE_26: CoverImage26,
  IMAGE_27: CoverImage27,
  IMAGE_28: CoverImage28,
  IMAGE_29: CoverImage29,
} as const;

export const DEFAULT_COVER_IMAGE_URL = STATIC_COVER_IMAGES.IMAGE_1;

/**
 * Set of static image URLs for fast O(1) lookup
 */
const STATIC_COVER_IMAGES_SET = new Set<string>(Object.values(STATIC_COVER_IMAGES));

export type TCoverImageType = "local_static" | "uploaded_asset" | "unsplash";

export type TCoverImageResult = {
  needsUpload: boolean;
  imageType: TCoverImageType;
  shouldUpdate: boolean;
};

export type TCoverImagePayload = {
  cover_image?: string | null;
  cover_image_url?: string | null;
  cover_image_asset?: string | null;
};

/**
 * Checks if a given URL is a valid static cover image
 */
export const isStaticCoverImage = (imageUrl: string | null | undefined): boolean => {
  if (!imageUrl) return false;
  return STATIC_COVER_IMAGES_SET.has(imageUrl);
};

/**
 * Determines the type of cover image URL
 * Uses explicit validation against known static images for better accuracy
 */
export const getCoverImageType = (imageUrl: string): TCoverImageType => {
  // Check against the explicit set of static images
  if (isStaticCoverImage(imageUrl)) return "local_static";

  // Check if it's an Unsplash image by validating the hostname
  try {
    const url = new URL(imageUrl);
    const hostname = url.hostname.toLowerCase();
    if (hostname === "unsplash.com" || hostname.endsWith(".unsplash.com")) {
      return "unsplash";
    }
  } catch {
    // If URL parsing fails (e.g., relative path), fall through to other checks
  }

  if (imageUrl.startsWith("http")) return "uploaded_asset";

  return "uploaded_asset";
};

/**
 * Gets the correct display URL for a cover image
 * - Local static images: returned as-is (served from assets folder)
 * - Uploaded assets: processed through getFileURL (adds backend URL)
 */
export function getCoverImageDisplayURL(imageUrl: string | null | undefined, fallbackUrl: string): string;
export function getCoverImageDisplayURL(imageUrl: string | null | undefined, fallbackUrl: null): string | null;
export function getCoverImageDisplayURL(
  imageUrl: string | null | undefined,
  fallbackUrl: string | null
): string | null {
  if (!imageUrl) {
    return fallbackUrl;
  }

  const imageType = getCoverImageType(imageUrl);

  if (imageType === "local_static" || imageType === "unsplash") {
    return imageUrl;
  }

  if (imageType === "uploaded_asset") {
    return getFileURL(imageUrl) || imageUrl;
  }

  return imageUrl;
}

/**
 * Analyzes cover image change and determines what action to take
 * Merged with isUnsplashImage logic - now detects unsplash images as a separate type
 */
export const analyzeCoverImageChange = (
  currentImage: string | null | undefined,
  newImage: string | null | undefined
): TCoverImageResult => {
  const hasChanged = currentImage !== newImage;

  if (!hasChanged) {
    return {
      needsUpload: false,
      imageType: "uploaded_asset",
      shouldUpdate: false,
    };
  }

  if (!newImage) {
    return {
      needsUpload: false,
      imageType: "uploaded_asset",
      shouldUpdate: true,
    };
  }

  const imageType = getCoverImageType(newImage);

  return {
    needsUpload: imageType === "local_static" || imageType === "unsplash",
    imageType,
    shouldUpdate: hasChanged,
  };
};

/**
 * Uploads a local static image to S3
 */
export const uploadCoverImage = async (
  imageUrl: string,
  uploadConfig: {
    workspaceSlug?: string;
    entityIdentifier: string;
    entityType: EFileAssetType;
    isUserAsset?: boolean;
  }
): Promise<string> => {
  const { workspaceSlug, entityIdentifier, entityType, isUserAsset = false } = uploadConfig;

  // Fetch the local image
  const response = await fetch(imageUrl);

  if (!response.ok) {
    throw new Error(`Failed to fetch image: ${response.statusText}`);
  }

  const blob = await response.blob();

  // Validate it's actually an image
  if (!blob.type.startsWith("image/")) {
    throw new Error("Invalid file type. Please select an image.");
  }

  const fileName = imageUrl.split("/").pop()?.split("?")[0] || "image.jpg";
  const file = new File([blob], fileName, { type: blob.type });

  // Upload based on context
  if (isUserAsset) {
    const uploadResult = await fileService.uploadUserAsset(
      {
        entity_identifier: entityIdentifier,
        entity_type: entityType,
      },
      file
    );
    return uploadResult.asset_url;
  } else {
    if (!workspaceSlug) {
      throw new Error("Workspace slug is required for workspace asset upload");
    }

    const uploadResult = await fileService.uploadWorkspaceAsset(
      workspaceSlug,
      {
        entity_identifier: entityIdentifier,
        entity_type: entityType,
      },
      file
    );
    return uploadResult.asset_url;
  }
};

/**
 * Main utility to handle cover image changes with upload
 */
export const handleCoverImageChange = async (
  currentImage: string | null | undefined,
  newImage: string | null | undefined,
  uploadConfig: {
    workspaceSlug?: string;
    entityIdentifier: string;
    entityType: EFileAssetType;
    isUserAsset?: boolean;
  }
): Promise<TCoverImagePayload | undefined> => {
  const analysis = analyzeCoverImageChange(currentImage, newImage);
  if (!analysis.shouldUpdate) return;

  if (!newImage) {
    return { cover_image: null, cover_image_url: null, cover_image_asset: null };
  }

  if (analysis.needsUpload) {
    const assetUrl = await uploadCoverImage(newImage, uploadConfig);
    // cover_image requires an absolute URL; cover_image_url is relative (matches GET /api/users/me/ format)
    return { cover_image: getFileURL(assetUrl) || assetUrl, cover_image_url: assetUrl };
  }

  // cover_image requires an absolute URL; getFileURL converts relative paths from the Upload tab
  return { cover_image: getFileURL(newImage) || newImage, cover_image_url: newImage };
};

/**
 * Returns a random cover image from the STATIC_COVER_IMAGES object
 * @returns {string} A random cover image URL
 */
export const getRandomCoverImage = (): string =>
  Object.values(STATIC_COVER_IMAGES)[Math.floor(Math.random() * Object.keys(STATIC_COVER_IMAGES).length)];
