use takumi::prelude::{Length::*, *};

use crate::test_utils::run_fixture_test;

fn create_container_with_background_clip(
  background_clip: BackgroundClip,
  background_color: Color,
  padding: f32,
  border_width: f32,
) -> Node {
  Node::container([Node::container([]).with_style(
    Style::default()
      .with(StyleDeclaration::display(Display::Flex))
      .with(StyleDeclaration::width(Rem(16.0)))
      .with(StyleDeclaration::height(Rem(10.0)))
      .with(StyleDeclaration::background_color(ColorInput::Value(
        background_color,
      )))
      .with(StyleDeclaration::background_clip(background_clip))
      .with_padding(Sides([Px(padding); 4]))
      .with_border_width(Sides([Px(border_width).into(); 4]))
      .with_border_style(Sides([BorderStyle::Solid; 4]))
      .with_border_color(Sides([ColorInput::Value(Color([0, 0, 0, 255])); 4]))
      .with_border_radius(BorderRadius(Sides([SpacePair::from_single(Px(8.0)); 4]))),
  )])
  .with_style(
    Style::default()
      .with(StyleDeclaration::display(Display::Flex))
      .with(StyleDeclaration::width(Percentage(100.0)))
      .with(StyleDeclaration::height(Percentage(100.0)))
      .with(StyleDeclaration::background_color(ColorInput::Value(
        Color([200, 200, 200, 255]),
      )))
      .with(StyleDeclaration::justify_content(JustifyContent::Center))
      .with(StyleDeclaration::align_items(AlignItems::Center)),
  )
}

#[test]
fn test_style_background_clip_border_box() {
  let container = create_container_with_background_clip(
    BackgroundClip::BorderBox,
    Color([255, 0, 0, 255]),
    20.0,
    10.0,
  );

  run_fixture_test(container, "style_background_clip_border_box");
}

#[test]
fn test_style_background_clip_padding_box() {
  let container = create_container_with_background_clip(
    BackgroundClip::PaddingBox,
    Color([0, 128, 255, 255]),
    20.0,
    10.0,
  );

  run_fixture_test(container, "style_background_clip_padding_box");
}

#[test]
fn test_style_background_clip_content_box() {
  let container = create_container_with_background_clip(
    BackgroundClip::ContentBox,
    Color([34, 197, 94, 255]),
    20.0,
    10.0,
  );

  run_fixture_test(container, "style_background_clip_content_box");
}

#[test]
fn test_style_background_clip_text_gradient() {
  let gradient_images = BackgroundImages::from_css_str(
    "linear-gradient(90deg, #ff3b30, #ffcc00, #34c759, #007aff, #5856d6)",
  )
  .unwrap();

  let container = Node::container([Node::text("Gradient Text".to_string()).with_style(
    Style::default()
      .with(StyleDeclaration::display(Display::Flex))
      .with(StyleDeclaration::background_image(Some(gradient_images)))
      .with(StyleDeclaration::background_size(
        BackgroundSizes::from_css_str("100% 100%").unwrap(),
      ))
      .with(StyleDeclaration::background_position(
        PositionValues::from_css_str("0 0").unwrap(),
      ))
      .with(StyleDeclaration::background_repeat(
        BackgroundRepeats::from_css_str("no-repeat").unwrap(),
      ))
      .with(StyleDeclaration::background_clip(BackgroundClip::Text))
      .with(StyleDeclaration::color(ColorInput::Value(
        Color::transparent(),
      ))),
  )])
  .with_style(
    Style::default()
      .with(StyleDeclaration::display(Display::Flex))
      .with(StyleDeclaration::background_color(ColorInput::Value(
        Color([240, 240, 240, 255]),
      )))
      .with(StyleDeclaration::width(Percentage(100.0)))
      .with(StyleDeclaration::height(Percentage(100.0)))
      .with(StyleDeclaration::font_size(Px(72.0).into()))
      .with(StyleDeclaration::align_items(AlignItems::Center))
      .with(StyleDeclaration::justify_content(JustifyContent::Center)),
  );

  run_fixture_test(container, "style_background_clip_text_gradient");
}

#[test]
fn test_style_background_clip_text_radial_gradient() {
  let gradient_images =
    BackgroundImages::from_css_str("radial-gradient(circle, #ff0080, #7928ca, #0070f3)").unwrap();

  let container = Node::container([Node::text("Radial Gradient".to_string()).with_style(
    Style::default()
      .with(StyleDeclaration::display(Display::Flex))
      .with(StyleDeclaration::background_image(Some(gradient_images)))
      .with(StyleDeclaration::background_size(
        BackgroundSizes::from_css_str("100% 100%").unwrap(),
      ))
      .with(StyleDeclaration::background_position(
        PositionValues::from_css_str("center center").unwrap(),
      ))
      .with(StyleDeclaration::background_clip(BackgroundClip::Text))
      .with(StyleDeclaration::color(ColorInput::Value(
        Color::transparent(),
      ))),
  )])
  .with_style(
    Style::default()
      .with(StyleDeclaration::display(Display::Flex))
      .with(StyleDeclaration::background_color(ColorInput::Value(
        Color([255, 255, 255, 255]),
      )))
      .with(StyleDeclaration::width(Percentage(100.0)))
      .with(StyleDeclaration::height(Percentage(100.0)))
      .with(StyleDeclaration::font_size(Px(64.0).into()))
      .with(StyleDeclaration::font_weight(FontWeight::from(700.0)))
      .with(StyleDeclaration::align_items(AlignItems::Center))
      .with(StyleDeclaration::justify_content(JustifyContent::Center)),
  );

  run_fixture_test(container, "style_background_clip_text_radial");
}

#[test]
fn test_style_background_clip_border_area() {
  let container = Node::container([Node::container([]).with_style(
    Style::default()
      .with(StyleDeclaration::display(Display::Flex))
      .with(StyleDeclaration::width(Rem(16.0)))
      .with(StyleDeclaration::height(Rem(10.0)))
      .with(StyleDeclaration::background_color(ColorInput::Value(
        Color([255, 165, 0, 255]),
      )))
      .with(StyleDeclaration::background_clip(
        BackgroundClip::BorderArea,
      ))
      .with_padding(Sides([Px(20.0); 4]))
      .with_border_width(Sides([Px(10.0).into(); 4]))
      .with_border_style(Sides([BorderStyle::Solid; 4]))
      .with_border_color(Sides([ColorInput::Value(Color([0, 0, 0, 128])); 4]))
      .with_border_radius(BorderRadius(Sides([SpacePair::from_single(Px(8.0)); 4]))),
  )])
  .with_style(
    Style::default()
      .with(StyleDeclaration::display(Display::Flex))
      .with(StyleDeclaration::width(Percentage(100.0)))
      .with(StyleDeclaration::height(Percentage(100.0)))
      .with(StyleDeclaration::background_color(ColorInput::Value(
        Color([200, 200, 200, 255]),
      )))
      .with(StyleDeclaration::justify_content(JustifyContent::Center))
      .with(StyleDeclaration::align_items(AlignItems::Center)),
  );

  run_fixture_test(container, "style_background_clip_border_area");
}

#[test]
fn test_style_background_clip_with_gradient_background() {
  let gradient_images =
    BackgroundImages::from_css_str("linear-gradient(135deg, #667eea 0%, #764ba2 100%)").unwrap();

  let container = Node::container([Node::container([]).with_style(
    Style::default()
      .with(StyleDeclaration::display(Display::Flex))
      .with(StyleDeclaration::width(Rem(16.0)))
      .with(StyleDeclaration::height(Rem(10.0)))
      .with(StyleDeclaration::background_image(Some(gradient_images)))
      .with(StyleDeclaration::background_position(
        PositionValues::from_css_str("center center").unwrap(),
      ))
      .with(StyleDeclaration::background_clip(
        BackgroundClip::PaddingBox,
      ))
      .with_padding(Sides([Px(30.0); 4]))
      .with_border_width(Sides([Px(15.0).into(); 4]))
      .with_border_style(Sides([BorderStyle::Solid; 4]))
      .with_border_color(Sides([ColorInput::Value(Color([255, 255, 255, 255])); 4])),
  )])
  .with_style(
    Style::default()
      .with(StyleDeclaration::display(Display::Flex))
      .with(StyleDeclaration::width(Percentage(100.0)))
      .with(StyleDeclaration::height(Percentage(100.0)))
      .with(StyleDeclaration::background_color(ColorInput::Value(
        Color([200, 200, 200, 255]),
      )))
      .with(StyleDeclaration::justify_content(JustifyContent::Center))
      .with(StyleDeclaration::align_items(AlignItems::Center)),
  );

  run_fixture_test(container, "style_background_clip_gradient_padding");
}

#[test]
fn test_style_background_clip_text_multiline() {
  let gradient_images =
    BackgroundImages::from_css_str("linear-gradient(45deg, #12c2e9, #c471ed, #f64f59)").unwrap();

  let container = Node::container([
      Node::text("This is a multiline text with a beautiful gradient background clipped to the text shape. It demonstrates how background-clip: text works with longer content.".to_string())
  .with_style(Style::default().with(StyleDeclaration::display(Display::Flex))
            .with(StyleDeclaration::background_image(Some(gradient_images)))
            .with(StyleDeclaration::background_size(BackgroundSizes::from_css_str("100% 100%").unwrap()))
            .with(StyleDeclaration::background_position(
              PositionValues::from_css_str("center center").unwrap(),
            ))
            .with(StyleDeclaration::background_clip(BackgroundClip::Text))
            .with(StyleDeclaration::color(ColorInput::Value(Color::transparent())))
            .with(StyleDeclaration::width(Percentage(100.0))),)

    ])
  .with_style(Style::default().with(StyleDeclaration::display(Display::Flex))
        .with(StyleDeclaration::background_color(ColorInput::Value(Color([255, 255, 255, 255]))))
        .with(StyleDeclaration::width(Percentage(100.0)))
        .with(StyleDeclaration::height(Percentage(100.0)))
        .with(StyleDeclaration::font_size(Px(48.0).into()))
        .with(StyleDeclaration::font_weight(FontWeight::from(800.0)))
        .with_padding(Sides([Px(40.0); 4])),);

  run_fixture_test(container, "style_background_clip_text_multiline");
}

#[test]
fn test_style_background_clip_comparison() {
  let container = Node::container([
    // Border Box
    Node::container([Node::text("border-box".to_string()).with_style(
      Style::default()
        .with(StyleDeclaration::display(Display::Flex))
        .with(StyleDeclaration::font_size(Px(20.0).into()))
        .with(StyleDeclaration::color(ColorInput::Value(Color::white()))),
    )])
    .with_style(
      Style::default()
        .with(StyleDeclaration::display(Display::Flex))
        .with(StyleDeclaration::width(Percentage(100.0)))
        .with(StyleDeclaration::height(Px(80.0)))
        .with(StyleDeclaration::background_color(ColorInput::Value(
          Color([255, 0, 0, 255]),
        )))
        .with(StyleDeclaration::background_clip(BackgroundClip::BorderBox))
        .with_padding(Sides([Px(15.0); 4]))
        .with_border_width(Sides([Px(8.0).into(); 4]))
        .with_border_style(Sides([BorderStyle::Solid; 4]))
        .with_border_color(Sides([ColorInput::Value(Color([0, 0, 0, 128])); 4])),
    ),
    // Padding Box
    Node::container([Node::text("padding-box".to_string()).with_style(
      Style::default()
        .with(StyleDeclaration::display(Display::Flex))
        .with(StyleDeclaration::font_size(Px(20.0).into()))
        .with(StyleDeclaration::color(ColorInput::Value(Color::white()))),
    )])
    .with_style(
      Style::default()
        .with(StyleDeclaration::display(Display::Flex))
        .with(StyleDeclaration::width(Percentage(100.0)))
        .with(StyleDeclaration::height(Px(80.0)))
        .with(StyleDeclaration::background_color(ColorInput::Value(
          Color([0, 128, 255, 255]),
        )))
        .with(StyleDeclaration::background_clip(
          BackgroundClip::PaddingBox,
        ))
        .with_padding(Sides([Px(15.0); 4]))
        .with_border_width(Sides([Px(8.0).into(); 4]))
        .with_border_style(Sides([BorderStyle::Solid; 4]))
        .with_border_color(Sides([ColorInput::Value(Color([0, 0, 0, 128])); 4])),
    ),
    // Content Box
    Node::container([Node::text("content-box".to_string()).with_style(
      Style::default()
        .with(StyleDeclaration::display(Display::Flex))
        .with(StyleDeclaration::font_size(Px(20.0).into()))
        .with(StyleDeclaration::color(ColorInput::Value(Color::white()))),
    )])
    .with_style(
      Style::default()
        .with(StyleDeclaration::display(Display::Flex))
        .with(StyleDeclaration::width(Percentage(100.0)))
        .with(StyleDeclaration::height(Px(80.0)))
        .with(StyleDeclaration::background_color(ColorInput::Value(
          Color([34, 197, 94, 255]),
        )))
        .with(StyleDeclaration::background_clip(
          BackgroundClip::ContentBox,
        ))
        .with_padding(Sides([Px(15.0); 4]))
        .with_border_width(Sides([Px(8.0).into(); 4]))
        .with_border_style(Sides([BorderStyle::Solid; 4]))
        .with_border_color(Sides([ColorInput::Value(Color([0, 0, 0, 128])); 4])),
    ),
  ])
  .with_style(
    Style::default()
      .with(StyleDeclaration::display(Display::Flex))
      .with(StyleDeclaration::width(Percentage(100.0)))
      .with(StyleDeclaration::height(Percentage(100.0)))
      .with(StyleDeclaration::background_color(ColorInput::Value(
        Color([240, 240, 240, 255]),
      )))
      .with(StyleDeclaration::display(Display::Flex))
      .with(StyleDeclaration::flex_direction(FlexDirection::Column))
      .with_gap(SpacePair::from_single(Px(20.0).into()))
      .with_padding(Sides([Px(20.0); 4])),
  );

  run_fixture_test(container, "style_background_clip_comparison");
}
