/*
 * Copyright 2025 Google LLC
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

using System.Collections.Generic;

namespace Firebase.AI
{
  /// <summary>
  /// An aspect ratio for images generated by Imagen.
  ///
  /// To specify an aspect ratio for generated images, set `AspectRatio` in
  /// your `ImagenGenerationConfig`. See the [Cloud
  /// documentation](https://cloud.google.com/vertex-ai/generative-ai/docs/image/generate-images#aspect-ratio)
  /// for more details and examples of the supported aspect ratios.
  /// </summary>
  public enum ImagenAspectRatio
  {
    /// <summary>
    /// Square (1:1) aspect ratio.
    ///
    /// Common uses for this aspect ratio include social media posts.
    /// </summary>
    Square1x1,
    /// <summary>
    /// Portrait widescreen (9:16) aspect ratio.
    ///
    /// This is the `Landscape16x9` aspect ratio rotated 90 degrees. This a relatively new aspect
    /// ratio that has been popularized by short form video apps (for example, YouTube shorts). Use
    /// this for tall objects with strong vertical orientations such as buildings, trees, waterfalls,
    /// or other similar objects.
    /// </summary>
    Portrait9x16,
    /// <summary>
    /// Widescreen (16:9) aspect ratio.
    ///
    /// This ratio has replaced `Landscape4x3` as the most common aspect ratio for TVs, monitors,
    /// and mobile phone screens (landscape). Use this aspect ratio when you want to capture more of
    /// the background (for example, scenic landscapes).
    /// </summary>
    Landscape16x9,
    /// <summary>
    /// Portrait full screen (3:4) aspect ratio.
    ///
    /// This is the `Landscape4x3` aspect ratio rotated 90 degrees. This lets to capture more of
    /// the scene vertically compared to the `Square1x1` aspect ratio.
    /// </summary>
    Portrait3x4,
    /// <summary>
    /// Fullscreen (4:3) aspect ratio.
    ///
    /// This aspect ratio is commonly used in media or film. It is also the dimensions of most old
    /// (non-widescreen) TVs and medium format cameras. It captures more of the scene horizontally
    /// (compared to `Square1x1`), making it a preferred aspect ratio for photography.
    /// </summary>
    Landscape4x3
  }

  /// <summary>
  /// An image format for images generated by Imagen.
  ///
  /// To specify an image format for generated images, set `ImageFormat` in
  /// your `ImagenGenerationConfig`. See the [Cloud
  /// documentation](https://cloud.google.com/vertex-ai/generative-ai/docs/model-reference/imagen-api#output-options)
  /// for more details.
  /// </summary>
  public readonly struct ImagenImageFormat
  {
#if !DOXYGEN
    public string MimeType { get; }
    public int? CompressionQuality { get; }
#endif

    private ImagenImageFormat(string mimeType, int? compressionQuality = null)
    {
      MimeType = mimeType;
      CompressionQuality = compressionQuality;
    }

    /// <summary>
    /// PNG image format.
    ///
    /// Portable Network Graphic (PNG) is a lossless image format, meaning no image data is lost
    /// during compression. Images in PNG format are *typically* larger than JPEG images, though this
    /// depends on the image content and JPEG compression quality.
    /// </summary>
    public static ImagenImageFormat Png()
    {
      return new ImagenImageFormat("image/png");
    }

    /// <summary>
    /// JPEG image format.
    ///
    /// Joint Photographic Experts Group (JPEG) is a lossy compression format, meaning some image data
    /// is discarded during compression. Images in JPEG format are *typically* larger than PNG images,
    /// though this depends on the image content and JPEG compression quality.
    /// </summary>
    /// <param name="compressionQuality">The JPEG quality setting from 0 to 100, where `0` is highest level of
    ///     compression (lowest image quality, smallest file size) and `100` is the lowest level of
    ///     compression (highest image quality, largest file size); defaults to `75`.</param>
    public static ImagenImageFormat Jpeg(int? compressionQuality = null)
    {
      return new ImagenImageFormat("image/jpeg", compressionQuality);
    }

    /// <summary>
    /// Intended for internal use only.
    /// This method is used for serializing the object to JSON for the API request.
    /// </summary>
    internal Dictionary<string, object> ToJson()
    {
      Dictionary<string, object> jsonDict = new()
      {
        ["mimeType"] = MimeType
      };
      if (CompressionQuality != null)
      {
        jsonDict["compressionQuality"] = CompressionQuality.Value;
      }
      return jsonDict;
    }
  }

  /// <summary>
  /// Configuration options for generating images with Imagen.
  ///
  /// See [Parameters for Imagen
  /// models](https://firebase.google.com/docs/vertex-ai/model-parameters?platform=unity#imagen) to
  /// learn about parameters available for use with Imagen models, including how to configure them.
  /// </summary>
  public readonly struct ImagenGenerationConfig
  {
#if !DOXYGEN
    public string NegativePrompt { get; }
    public int? NumberOfImages { get; }
    public ImagenAspectRatio? AspectRatio { get; }
    public ImagenImageFormat? ImageFormat { get; }
    public bool? AddWatermark { get; }
#endif

    /// <summary>
    /// Initializes configuration options for generating images with Imagen.
    /// </summary>
    /// <param name="negativePrompt">Specifies elements to exclude from the generated image;
    ///     disabled if not specified.</param>
    /// <param name="numberOfImages">The number of image samples to generate;
    ///     defaults to 1 if not specified.</param>
    /// <param name="aspectRatio">The aspect ratio of generated images;
    ///     defaults to to square, 1:1.</param>
    /// <param name="imageFormat">The image format of generated images;
    ///     defaults to PNG.</param>
    /// <param name="addWatermark">Whether to add an invisible watermark to generated images;
    ///     the default value depends on the model.</param>
    public ImagenGenerationConfig(
        string negativePrompt = null,
        int? numberOfImages = null,
        ImagenAspectRatio? aspectRatio = null,
        ImagenImageFormat? imageFormat = null,
        bool? addWatermark = null)
    {
      NegativePrompt = negativePrompt;
      NumberOfImages = numberOfImages;
      AspectRatio = aspectRatio;
      ImageFormat = imageFormat;
      AddWatermark = addWatermark;
    }

    private static string ConvertAspectRatio(ImagenAspectRatio aspectRatio)
    {
      return aspectRatio switch
      {
        ImagenAspectRatio.Square1x1 => "1:1",
        ImagenAspectRatio.Portrait9x16 => "9:16",
        ImagenAspectRatio.Landscape16x9 => "16:9",
        ImagenAspectRatio.Portrait3x4 => "3:4",
        ImagenAspectRatio.Landscape4x3 => "4:3",
        _ => aspectRatio.ToString(), // Fallback
      };
    }

    /// <summary>
    /// Intended for internal use only.
    /// This method is used for serializing the object to JSON for the API request.
    /// </summary>
    internal Dictionary<string, object> ToJson()
    {
      Dictionary<string, object> jsonDict = new()
      {
        ["sampleCount"] = NumberOfImages ?? 1
      };
      if (!string.IsNullOrEmpty(NegativePrompt))
      {
        jsonDict["negativePrompt"] = NegativePrompt;
      }
      if (AspectRatio != null)
      {
        jsonDict["aspectRatio"] = ConvertAspectRatio(AspectRatio.Value);
      }
      if (ImageFormat != null)
      {
        jsonDict["outputOptions"] = ImageFormat?.ToJson();
      }
      if (AddWatermark != null)
      {
        jsonDict["addWatermark"] = AddWatermark.Value;
      }

      return jsonDict;
    }
  }

}
