// Copyright 2025 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.

///|
/// Legend support for diago diagrams
///
/// Legends provide a visual key explaining the meaning of shapes and
/// connections used in the diagram.

///|
/// Position of the legend in the diagram
pub(all) enum LegendPosition {
  TopLeft
  TopRight
  BottomLeft
  BottomRight
  /// Legend is not displayed
  Hidden
} derive(Eq, Debug)

///|
/// Parse legend position from string
pub fn LegendPosition::from_string(s : String) -> LegendPosition {
  match s.to_lower() {
    "top-left" | "topleft" | "tl" => TopLeft
    "top-right" | "topright" | "tr" => TopRight
    "bottom-left" | "bottomleft" | "bl" => BottomLeft
    "bottom-right" | "bottomright" | "br" => BottomRight
    "hidden" | "none" => Hidden
    _ => BottomRight // Default position
  }
}

///|
/// Convert legend position to string
pub fn LegendPosition::to_position_string(self : LegendPosition) -> String {
  match self {
    TopLeft => "top-left"
    TopRight => "top-right"
    BottomLeft => "bottom-left"
    BottomRight => "bottom-right"
    Hidden => "hidden"
  }
}

///|
/// A single entry in the legend
pub(all) enum LegendEntry {
  /// A shape entry with optional custom style
  ShapeEntry(
    id~ : String,
    shape~ : ShapeType,
    label~ : String,
    style~ : StyleInput?
  )
  /// A connection/edge entry showing arrowheads
  ConnectionEntry(
    src_id~ : String,
    dst_id~ : String,
    index~ : Int,
    src_arrow_enabled~ : Bool,
    dst_arrow_enabled~ : Bool,
    src_arrow~ : ArrowheadType,
    dst_arrow~ : ArrowheadType,
    label~ : String,
    style~ : StyleInput?
  )
  /// A custom entry with icon URL or symbol
  CustomEntry(icon~ : String, label~ : String)
  /// A visual separator line
  Separator
} derive(Debug)

///|
/// Create a shape legend entry
pub fn LegendEntry::shape(
  shape : ShapeType,
  label : String,
  style : StyleInput?,
  id? : String = label,
) -> LegendEntry {
  ShapeEntry(id~, shape~, label~, style~)
}

///|
/// Create a connection legend entry
pub fn LegendEntry::connection(
  src_arrow : ArrowheadType,
  dst_arrow : ArrowheadType,
  label : String,
  style : StyleInput?,
  src_id? : String = "src",
  dst_id? : String = "dst",
  index? : Int = 0,
  src_arrow_enabled? : Bool = src_arrow != None,
  dst_arrow_enabled? : Bool = dst_arrow != None,
) -> LegendEntry {
  ConnectionEntry(
    src_id~,
    dst_id~,
    index~,
    src_arrow_enabled~,
    dst_arrow_enabled~,
    src_arrow~,
    dst_arrow~,
    label~,
    style~,
  )
}

///|
/// Create a custom legend entry
pub fn LegendEntry::custom(icon : String, label : String) -> LegendEntry {
  CustomEntry(icon~, label~)
}

///|
/// Create a separator entry
pub fn LegendEntry::separator() -> LegendEntry {
  Separator
}

///|
/// The legend configuration for a diagram
pub struct Legend {
  /// Optional title for the legend
  title : String?
  /// Position of the legend in the diagram
  position : LegendPosition
  /// Legend entries
  entries : Array[LegendEntry]
  /// Background fill color
  fill : String?
  /// Border stroke color
  stroke : String?
  /// Padding inside the legend box
  padding : Double
  /// Gap between entries
  entry_gap : Double
  /// Size of shape icons in legend
  icon_size : Double
} derive(Debug)

///|
/// Create a new legend with default settings
pub fn Legend::new() -> Legend {
  {
    title: None,
    position: BottomRight,
    entries: [],
    fill: Some("#ffffff"),
    stroke: Some("#DEE1EB"),
    padding: 20.0,
    entry_gap: 15.0,
    icon_size: 24.0,
  }
}

///|
/// Create a legend with a specific position
pub fn Legend::with_position(position : LegendPosition) -> Legend {
  let legend = Legend::new()
  { ..legend, position, }
}

///|
/// Add an entry to the legend
pub fn Legend::add_entry(self : Legend, entry : LegendEntry) -> Unit {
  self.entries.push(entry)
}

///|
/// Add a shape entry to the legend
pub fn Legend::add_shape(
  self : Legend,
  shape : ShapeType,
  label : String,
) -> Unit {
  self.entries.push(LegendEntry::shape(shape, label, None))
}

///|
/// Add a connection entry to the legend
pub fn Legend::add_connection(
  self : Legend,
  src_arrow : ArrowheadType,
  dst_arrow : ArrowheadType,
  label : String,
) -> Unit {
  self.entries.push(LegendEntry::connection(src_arrow, dst_arrow, label, None))
}

///|
/// Add a separator to the legend
pub fn Legend::add_separator(self : Legend) -> Unit {
  self.entries.push(LegendEntry::separator())
}

///|
pub fn Legend::set_title(self : Legend, title : String) -> Legend {
  { ..self, title: Some(title) }
}

///|
pub fn Legend::set_position(self : Legend, position : LegendPosition) -> Legend {
  { ..self, position, }
}

///|
pub fn Legend::set_fill(self : Legend, fill : String) -> Legend {
  { ..self, fill: Some(fill) }
}

///|
pub fn Legend::set_stroke(self : Legend, stroke : String) -> Legend {
  { ..self, stroke: Some(stroke) }
}

///|
pub fn Legend::set_padding(self : Legend, padding : Double) -> Legend {
  { ..self, padding, }
}

///|
pub fn Legend::set_entry_gap(self : Legend, entry_gap : Double) -> Legend {
  { ..self, entry_gap, }
}

///|
pub fn Legend::set_icon_size(self : Legend, icon_size : Double) -> Legend {
  { ..self, icon_size, }
}

///|
/// Check if legend has any entries
pub fn Legend::is_empty(self : Legend) -> Bool {
  self.entries.is_empty()
}

///|
/// Get the number of entries (excluding separators)
pub fn Legend::entry_count(self : Legend) -> Int {
  let mut count = 0
  for entry in self.entries {
    match entry {
      Separator => ()
      _ => count += 1
    }
  }
  count
}