//! Buttons style

#![allow(clippy::module_name_repetitions)]

use iced::border::Radius;
use iced::widget::button;
use iced::widget::button::{Catalog, Status, Style};
use iced::{Background, Border, Color, Shadow, Vector};

use crate::StyleType;
use crate::gui::styles::style_constants::{BORDER_BUTTON_RADIUS, BORDER_WIDTH};
use crate::gui::styles::types::gradient_type::{
    GradientType, get_gradient_buttons, get_gradient_hovered_buttons,
};
use crate::gui::styles::types::palette::mix_colors;

#[derive(Default)]
pub enum ButtonType {
    #[default]
    Standard,
    BorderedRound,
    BorderedRoundSelected,
    TabActive,
    TabInactive,
    Starred,
    NotStarred,
    Neutral,
    Alert,
    Gradient(GradientType),
    SortArrows,
    SortArrowActive,
    Thumbnail,
}

impl ButtonType {
    fn active(&self, style: &StyleType) -> Style {
        let colors = style.get_palette();
        let ext = style.get_extension();
        button::Style {
            background: Some(match self {
                ButtonType::TabActive | ButtonType::BorderedRoundSelected => {
                    Background::Color(mix_colors(colors.primary, ext.buttons_color))
                }
                ButtonType::BorderedRound => Background::Color(Color {
                    a: ext.alpha_round_containers,
                    ..ext.buttons_color
                }),
                ButtonType::Neutral
                | ButtonType::Thumbnail
                | ButtonType::Starred
                | ButtonType::NotStarred
                | ButtonType::SortArrows
                | ButtonType::SortArrowActive => Background::Color(Color::TRANSPARENT),
                ButtonType::Gradient(GradientType::None) => Background::Color(colors.secondary),
                ButtonType::Gradient(gradient_type) => Background::Gradient(get_gradient_buttons(
                    &colors,
                    *gradient_type,
                    ext.is_nightly,
                    1.0,
                )),
                _ => Background::Color(ext.buttons_color),
            }),
            border: Border {
                radius: match self {
                    ButtonType::Neutral => 0.0.into(),
                    ButtonType::TabActive | ButtonType::TabInactive => Radius::new(0).bottom(30),
                    ButtonType::BorderedRound
                    | ButtonType::BorderedRoundSelected
                    | ButtonType::Gradient(_) => 12.0.into(),
                    ButtonType::Starred | ButtonType::NotStarred => 100.0.into(),
                    _ => BORDER_BUTTON_RADIUS.into(),
                },
                width: match self {
                    ButtonType::TabActive
                    | ButtonType::TabInactive
                    | ButtonType::SortArrows
                    | ButtonType::SortArrowActive
                    | ButtonType::Starred
                    | ButtonType::NotStarred
                    | ButtonType::Neutral
                    | ButtonType::Thumbnail => 0.0,
                    ButtonType::BorderedRound => BORDER_WIDTH * 2.0,
                    _ => BORDER_WIDTH,
                },
                color: match self {
                    ButtonType::Alert => ext.red_alert_color,
                    ButtonType::BorderedRound => Color {
                        a: ext.alpha_round_borders,
                        ..ext.buttons_color
                    },
                    _ => colors.secondary,
                },
            },
            text_color: match self {
                ButtonType::Starred => colors.starred,
                ButtonType::SortArrows => Color {
                    a: ext.alpha_chart_badge,
                    ..colors.text_body
                },
                ButtonType::SortArrowActive => colors.secondary,
                ButtonType::Gradient(_) => colors.text_headers,
                ButtonType::Thumbnail => mix_colors(colors.text_headers, colors.secondary),
                _ => colors.text_body,
            },
            shadow: match self {
                ButtonType::TabActive | ButtonType::TabInactive => Shadow {
                    color: Color::BLACK,
                    offset: Vector::new(3.0, 2.0),
                    blur_radius: 4.0,
                },
                _ => Shadow::default(),
            },
            snap: true,
        }
    }

    fn hovered(&self, style: &StyleType) -> Style {
        let colors = style.get_palette();
        let ext = style.get_extension();
        button::Style {
            shadow: match self {
                ButtonType::Neutral
                | ButtonType::SortArrows
                | ButtonType::SortArrowActive
                | ButtonType::Thumbnail => Shadow::default(),
                _ => Shadow {
                    color: Color::BLACK,
                    offset: match self {
                        ButtonType::TabActive | ButtonType::TabInactive => Vector::new(3.0, 3.0),
                        _ => Vector::new(0.0, 2.0),
                    },
                    blur_radius: match self {
                        ButtonType::TabActive | ButtonType::TabInactive => 4.0,
                        _ => 2.0,
                    },
                },
            },
            background: Some(match self {
                ButtonType::SortArrows | ButtonType::SortArrowActive | ButtonType::Thumbnail => {
                    Background::Color(Color::TRANSPARENT)
                }
                ButtonType::Neutral => Background::Color(Color {
                    a: ext.alpha_round_borders,
                    ..ext.buttons_color
                }),
                ButtonType::Gradient(GradientType::None) => {
                    Background::Color(mix_colors(colors.primary, colors.secondary))
                }
                ButtonType::Gradient(gradient_type) => Background::Gradient(
                    get_gradient_hovered_buttons(&colors, *gradient_type, ext.is_nightly),
                ),
                ButtonType::BorderedRoundSelected => Background::Color(ext.buttons_color),
                _ => Background::Color(mix_colors(colors.primary, ext.buttons_color)),
            }),
            border: Border {
                radius: match self {
                    ButtonType::Neutral => 0.0.into(),
                    ButtonType::TabActive | ButtonType::TabInactive => Radius::new(0).bottom(30),
                    ButtonType::BorderedRound
                    | ButtonType::BorderedRoundSelected
                    | ButtonType::Gradient(_) => 12.0.into(),
                    ButtonType::Starred | ButtonType::NotStarred => 100.0.into(),
                    _ => BORDER_BUTTON_RADIUS.into(),
                },
                width: match self {
                    ButtonType::Starred
                    | ButtonType::NotStarred
                    | ButtonType::TabActive
                    | ButtonType::SortArrows
                    | ButtonType::SortArrowActive
                    | ButtonType::TabInactive
                    | ButtonType::Thumbnail
                    | ButtonType::BorderedRound => 0.0,
                    _ => BORDER_WIDTH,
                },
                color: match self {
                    ButtonType::Alert => ext.red_alert_color,
                    ButtonType::BorderedRound => Color {
                        a: ext.alpha_round_borders,
                        ..ext.buttons_color
                    },
                    ButtonType::Neutral => ext.buttons_color,
                    _ => colors.secondary,
                },
            },
            text_color: match self {
                ButtonType::Starred => colors.starred,
                ButtonType::Gradient(_) | ButtonType::Thumbnail => colors.text_headers,
                ButtonType::SortArrowActive | ButtonType::SortArrows => colors.secondary,
                _ => colors.text_body,
            },
            snap: true,
        }
    }

    fn disabled(&self, style: &StyleType) -> Style {
        let colors = style.get_palette();
        let ext = style.get_extension();
        match self {
            ButtonType::Gradient(_) => Style {
                background: Some(match self {
                    ButtonType::Gradient(GradientType::None) => Background::Color(Color {
                        a: ext.alpha_chart_badge,
                        ..colors.secondary
                    }),
                    ButtonType::Gradient(gradient_type) => {
                        Background::Gradient(get_gradient_buttons(
                            &colors,
                            *gradient_type,
                            ext.is_nightly,
                            ext.alpha_chart_badge,
                        ))
                    }
                    _ => Background::Color(ext.buttons_color),
                }),
                border: Border {
                    radius: 12.0.into(),
                    width: BORDER_WIDTH,
                    color: Color {
                        a: ext.alpha_chart_badge,
                        ..colors.secondary
                    },
                },
                text_color: Color {
                    a: 0.5,
                    ..colors.text_headers
                },
                shadow: Shadow::default(),
                snap: true,
            },
            ButtonType::Standard => Style {
                background: Some(Background::Color(Color {
                    a: ext.alpha_chart_badge,
                    ..ext.buttons_color
                })),
                border: Border {
                    radius: BORDER_BUTTON_RADIUS.into(),
                    width: BORDER_WIDTH,
                    color: Color {
                        a: ext.alpha_chart_badge,
                        ..colors.secondary
                    },
                },
                text_color: Color {
                    a: ext.alpha_chart_badge,
                    ..colors.text_body
                },
                shadow: Shadow::default(),
                snap: true,
            },
            _ => self.active(style),
        }
    }
}

impl Catalog for StyleType {
    type Class<'a> = ButtonType;

    fn default<'a>() -> Self::Class<'a> {
        Self::Class::default()
    }

    fn style(&self, class: &Self::Class<'_>, status: Status) -> Style {
        match status {
            Status::Active | Status::Pressed => class.active(self),
            Status::Hovered => class.hovered(self),
            Status::Disabled => class.disabled(self),
        }
    }
}
