// Copyright 2026 International Digital Economy Academy
//
// 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.

///|
/// One explicit opaque sRGB8 background for future perceptual compositing.
pub struct PerceptualBackground {
  red : Int
  green : Int
  blue : Int
} derive(ToJson, Eq)

///|
/// Parse one deterministic opaque sRGB color for perceptual compositing.
pub fn PerceptualBackground::parse_srgb(
  source : String,
) -> PerceptualBackground? {
  match @css_color.parse_solid_color(source) {
    Resolved(color) if color.alpha == 1.0 =>
      Some({ red: color.red, green: color.green, blue: color.blue })
    _ => None
  }
}

///|
pub fn PerceptualBackground::red(self : PerceptualBackground) -> Int {
  self.red
}

///|
pub fn PerceptualBackground::green(self : PerceptualBackground) -> Int {
  self.green
}

///|
pub fn PerceptualBackground::blue(self : PerceptualBackground) -> Int {
  self.blue
}

///|
/// Explicit LDR-FLIP viewing conditions with a bounded filter domain.
pub struct FlipViewingConditions {
  pixels_per_degree : Double
} derive(ToJson, Eq)

///|
/// Construct supported LDR-FLIP viewing conditions.
pub fn FlipViewingConditions::from_pixels_per_degree(
  pixels_per_degree : Double,
) -> FlipViewingConditions? {
  if pixels_per_degree.is_nan() ||
    pixels_per_degree.is_inf() ||
    pixels_per_degree < 1.0 ||
    pixels_per_degree > 4096.0 {
    None
  } else {
    Some({ pixels_per_degree, })
  }
}

///|
pub fn FlipViewingConditions::pixels_per_degree(
  self : FlipViewingConditions,
) -> Double {
  self.pixels_per_degree
}

///|
/// Explicit optional reporting threshold for LDR-FLIP error values.
pub struct FlipErrorThreshold {
  value : Double
} derive(ToJson, Eq)

///|
/// Construct one finite FLIP reporting threshold in the metric's `[0, 1]` range.
pub fn FlipErrorThreshold::from_value(value : Double) -> FlipErrorThreshold? {
  if value.is_nan() || value.is_inf() || value < 0.0 || value > 1.0 {
    None
  } else {
    Some({ value, })
  }
}

///|
pub fn FlipErrorThreshold::value(self : FlipErrorThreshold) -> Double {
  self.value
}

///|
/// Rendering and normalization conditions recorded for one comparison.
///
/// The root schema `2.0` API accepts caller-provided viewport dimensions,
/// Perceptual Background, FLIP Viewing Conditions, and FLIP error threshold,
/// and canonicalizes the
/// remaining fields to `v1_default`.
pub(all) struct ComparisonProfile {
  viewport_width : Int
  viewport_height : Int
  comparison_dpr : Double
  color_interpretation : String
  raster_representation : String
  renderer_id : String
  renderer_conformance_profile_id : String
  perceptual_background : PerceptualBackground?
  flip_viewing_conditions : FlipViewingConditions?
  flip_error_threshold : FlipErrorThreshold?
}

///|
pub impl ToJson for ComparisonProfile with fn to_json(self) {
  let fields : Map[String, Json] = Map([])
  fields["viewport_width"] = self.viewport_width.to_json()
  fields["viewport_height"] = self.viewport_height.to_json()
  fields["comparison_dpr"] = self.comparison_dpr.to_json()
  fields["color_interpretation"] = self.color_interpretation.to_json()
  fields["raster_representation"] = self.raster_representation.to_json()
  fields["renderer_id"] = self.renderer_id.to_json()
  fields["renderer_conformance_profile_id"] = self.renderer_conformance_profile_id.to_json()
  fields["perceptual_background"] = nullable_report_value(
    self.perceptual_background,
  )
  fields["flip_viewing_conditions"] = nullable_report_value(
    self.flip_viewing_conditions,
  )
  fields["flip_error_threshold"] = nullable_report_value(
    self.flip_error_threshold,
  )
  Json::object(fields)
}

///|
/// Return the fixed schema `2.0` profile with a `16 x 16` viewport.
///
/// Callers may copy the record with different positive viewport dimensions,
/// an explicitly parsed Perceptual Background, invariant-checked FLIP Viewing
/// Conditions, or an invariant-checked FLIP error threshold.
pub fn ComparisonProfile::v1_default() -> ComparisonProfile {
  {
    viewport_width: 16,
    viewport_height: 16,
    comparison_dpr: 1.0,
    color_interpretation: "srgb",
    raster_representation: "linear_srgb_premultiplied_rgba_f64",
    renderer_id: "svgdiff/residual-paint-normalizer@1+opacity-used-value-normalizer@1+length-unit-normalizer@1+shape-css-points-normalizer@1+stroke-length-normalizer@1+mask-edge-semantics-normalizer@1+isolated-group-compositor@1+static-mask-compositor@1+empty-filter-outcome-adapter@1+static-blend-compositor@1+Milky2018/svg@0.3.1",
    renderer_conformance_profile_id: "svgdiff-renderer-conformance-profile/27",
    perceptual_background: None,
    flip_viewing_conditions: None,
    flip_error_threshold: None,
  }
}