use ely_browser_core::BrowserSnapshot;
use ely_design_system::colors;
use ely_domain::{ThemeMode, WallpaperTheme};
use gpui::{
    AnyElement, Context, FontWeight, Hsla, InteractiveElement, IntoElement, ParentElement,
    SharedString, StatefulInteractiveElement, Styled, div, hsla, linear_color_stop,
    linear_gradient, prelude::FluentBuilder, px, rgb, rgba,
};
use gpui_component::{IconName, scroll::ScrollableElement, slider::Slider};

use super::appearance_layout_cards::render_sidebar_layout_section;

use crate::shell::ElyShell;
use crate::shell::chrome::SERIF_FAMILY;

pub(crate) fn render_appearance_form(
    shell: &mut ElyShell,
    snapshot: &BrowserSnapshot,
    cx: &mut Context<ElyShell>,
) -> AnyElement {
    div()
        .flex_1()
        .h_full()
        .overflow_y_scrollbar()
        .pt(px(28.0))
        .px(px(40.0))
        .pb(px(32.0))
        .child(
            div()
                .max_w(px(780.0))
                .mx_auto()
                .flex()
                .flex_col()
                .gap(px(28.0))
                .child(render_header())
                .child(render_wallpaper_grid(snapshot, cx))
                .child(render_appearance_rows(shell, snapshot, cx))
                .child(render_translucency_presets(cx))
                .child(render_sidebar_layout_section(snapshot, cx)),
        )
        .into_any_element()
}

fn render_header() -> AnyElement {
    div()
        .flex()
        .flex_col()
        .gap(px(6.0))
        .child(
            div()
                .text_size(px(11.0))
                .text_color(rgb(colors::INK_4))
                .child("GENERAL"),
        )
        .child(
            div()
                .font_family(SERIF_FAMILY)
                .text_size(px(34.0))
                .font_weight(FontWeight(400.0))
                .text_color(rgb(colors::INK))
                .child("Appearance"),
        )
        .child(
            div()
                .max_w(px(520.0))
                .text_size(px(13.0))
                .text_color(rgb(colors::INK_3))
                .child(
                    "Tune the atmosphere of your browser. ELY's wallpaper sets the ambient \
                     palette of every surface; pick one and let it breathe.",
                ),
        )
        .into_any_element()
}

fn render_wallpaper_grid(
    snapshot: &BrowserSnapshot,
    cx: &mut Context<ElyShell>,
) -> AnyElement {
    let active = snapshot.appearance.wallpaper();
    div()
        .grid()
        .grid_cols(4)
        .gap(px(10.0))
        .child(render_wallpaper_swatch(WallpaperTheme::Dawn, active, cx))
        .child(render_wallpaper_swatch(WallpaperTheme::Violet, active, cx))
        .child(render_wallpaper_swatch(WallpaperTheme::Mint, active, cx))
        .child(render_wallpaper_swatch(WallpaperTheme::Slate, active, cx))
        .into_any_element()
}

fn render_wallpaper_swatch(
    theme: WallpaperTheme,
    active: WallpaperTheme,
    cx: &mut Context<ElyShell>,
) -> AnyElement {
    let label = wallpaper_label(theme);
    let id = SharedString::from(format!("wallpaper-{}", label.to_ascii_lowercase()));
    let selected = theme == active;
    let (upper, lower, base) = swatch_colors(theme);

    div()
        .id(id)
        .flex()
        .flex_col()
        .gap(px(8.0))
        .cursor_pointer()
        .hover(|style| style.opacity(0.94))
        .active(|style| style.opacity(0.85))
        .on_click(cx.listener(move |shell, _, _, cx| {
            shell.set_wallpaper_theme(theme, cx);
        }))
        .child(
            div()
                .h(px(96.0))
                .rounded(px(10.0))
                .when(selected, |el| {
                    el.border_2().border_color(rgb(colors::ACCENT))
                })
                .when(!selected, |el| {
                    el.border_1().border_color(rgba(colors::STROKE))
                })
                .relative()
                .overflow_hidden()
                .bg(rgb(base))
                .child(
                    div()
                        .absolute()
                        .inset_0()
                        .bg(linear_gradient(
                            225.0,
                            linear_color_stop(upper, 0.0),
                            linear_color_stop(transparent_like(upper), 0.6),
                        )),
                )
                .child(
                    div()
                        .absolute()
                        .inset_0()
                        .bg(linear_gradient(
                            45.0,
                            linear_color_stop(lower, 0.0),
                            linear_color_stop(transparent_like(lower), 0.6),
                        )),
                ),
        )
        .child(
            div()
                .flex()
                .items_center()
                .gap(px(6.0))
                .text_size(px(12.0))
                .child(
                    div()
                        .flex_1()
                        .font_weight(FontWeight(500.0))
                        .text_color(rgb(colors::INK))
                        .child(label),
                )
                .when(selected, |el| {
                    el.child(
                        div()
                            .text_color(rgb(colors::ACCENT))
                            .child(IconName::Check),
                    )
                }),
        )
        .into_any_element()
}

fn render_appearance_rows(
    shell: &mut ElyShell,
    snapshot: &BrowserSnapshot,
    cx: &mut Context<ElyShell>,
) -> AnyElement {
    let appearance = snapshot.appearance;

    div()
        .flex()
        .flex_col()
        .child(render_theme_mode_row(appearance.theme_mode(), cx))
        .child(render_accent_row())
        .child(render_translucency_row(shell, appearance.translucency_pct()))
        .child(render_reduce_motion_row(appearance.reduce_motion(), cx))
        .child(render_reset_row(cx))
        .into_any_element()
}

fn render_translucency_row(
    shell: &mut ElyShell,
    pct: u8,
) -> AnyElement {
    let slider_state = shell.translucency_slider.clone();
    settings_row(
        "Translucency",
        "Glass density of sidebar & panels.",
        div()
            .flex()
            .items_center()
            .gap(px(10.0))
            .child(div().w(px(160.0)).child(Slider::new(&slider_state)))
            .child(
                div()
                    .min_w(px(36.0))
                    .text_size(px(11.0))
                    .text_color(rgb(colors::INK_3))
                    .child(format!("{pct}%")),
            )
            .into_any_element(),
    )
}

fn render_translucency_presets(cx: &mut Context<ElyShell>) -> AnyElement {
    div()
        .flex()
        .items_center()
        .gap(px(8.0))
        .pt(px(2.0))
        .child(
            div()
                .text_size(px(10.5))
                .text_color(rgb(colors::INK_4))
                .child("Presets"),
        )
        .child(translucency_preset("Solid", 0, cx))
        .child(translucency_preset("Default", 40, cx))
        .child(translucency_preset("Glassy", 75, cx))
        .into_any_element()
}

fn translucency_preset(
    label: &'static str,
    target_pct: u8,
    cx: &mut Context<ElyShell>,
) -> AnyElement {
    let id = SharedString::from(format!("translucency-{}", label.to_ascii_lowercase()));

    div()
        .id(id)
        .px(px(10.0))
        .py(px(4.0))
        .rounded(px(6.0))
        .bg(rgba(SEGMENT_BG))
        .text_size(px(11.5))
        .font_weight(FontWeight(500.0))
        .text_color(rgb(colors::INK_2))
        .cursor_pointer()
        .hover(|style| style.opacity(0.92))
        .active(|style| style.opacity(0.82))
        .on_click(cx.listener(move |shell, _, window, cx| {
            shell.set_translucency_pct_from_preset(target_pct, window, cx);
        }))
        .child(label)
        .into_any_element()
}

fn render_theme_mode_row(
    active: ThemeMode,
    cx: &mut Context<ElyShell>,
) -> AnyElement {
    settings_row(
        "Theme mode",
        "Match system appearance, or pick one to lock.",
        div()
            .flex()
            .items_center()
            .gap(px(2.0))
            .p(px(2.0))
            .rounded(px(8.0))
            .bg(rgba(SEGMENT_BG))
            .child(theme_segment("System", ThemeMode::System, active, cx))
            .child(theme_segment("Light", ThemeMode::Light, active, cx))
            .child(theme_segment("Dark", ThemeMode::Dark, active, cx))
            .into_any_element(),
    )
}

fn theme_segment(
    label: &'static str,
    mode: ThemeMode,
    active: ThemeMode,
    cx: &mut Context<ElyShell>,
) -> AnyElement {
    let selected = mode == active;
    let bg = if selected { 0xffffffff } else { 0x00000000 };
    let id = SharedString::from(format!("theme-mode-{}", label.to_ascii_lowercase()));

    div()
        .id(id)
        .px(px(12.0))
        .py(px(4.0))
        .rounded(px(6.0))
        .text_size(px(12.0))
        .font_weight(FontWeight(500.0))
        .text_color(rgb(colors::INK_2))
        .bg(rgba(bg))
        .cursor_pointer()
        .hover(|style| style.opacity(0.92))
        .active(|style| style.opacity(0.82))
        .on_click(cx.listener(move |shell, _, _, cx| {
            shell.set_theme_mode(mode, cx);
        }))
        .child(label)
        .into_any_element()
}

fn render_accent_row() -> AnyElement {
    settings_row(
        "Accent color",
        "Used across selection, focus rings & links.",
        div()
            .flex()
            .items_center()
            .gap(px(8.0))
            .child(swatch(colors::ACCENT, true))
            .child(swatch(0xec6a8e, false))
            .child(swatch(0x7c6cf7, false))
            .child(swatch(0x4fb59a, false))
            .child(swatch(colors::INK, false))
            .into_any_element(),
    )
}

fn swatch(color: u32, selected: bool) -> AnyElement {
    let mut element = div()
        .size(px(22.0))
        .rounded_full()
        .bg(rgb(color))
        .border_1()
        .border_color(rgba(0x0000000d));
    if selected {
        element = element
            .border_2()
            .border_color(rgb(colors::ACCENT));
    }
    element.into_any_element()
}

fn render_reduce_motion_row(reduce: bool, cx: &mut Context<ElyShell>) -> AnyElement {
    settings_row(
        "Reduce motion",
        "Mute transitions and ambient effects.",
        div()
            .id(SharedString::from("toggle-reduce-motion"))
            .w(px(34.0))
            .h(px(20.0))
            .rounded_full()
            .bg(if reduce { rgb(colors::ACCENT) } else { rgba(0x281e1426) })
            .p(px(2.0))
            .cursor_pointer()
            .hover(|style| style.opacity(0.9))
            .active(|style| style.opacity(0.78))
            .on_click(cx.listener(|shell, _, _, cx| shell.toggle_reduce_motion(cx)))
            .child(
                div()
                    .size(px(16.0))
                    .rounded_full()
                    .bg(rgb(0xffffff))
                    .when(reduce, |el| el.ml(px(14.0))),
            )
            .into_any_element(),
    )
}

fn render_reset_row(cx: &mut Context<ElyShell>) -> AnyElement {
    settings_row(
        "Restore defaults",
        "Reset wallpaper, theme mode, and motion to defaults.",
        div()
            .id(SharedString::from("appearance-reset"))
            .px(px(12.0))
            .py(px(7.0))
            .rounded(px(8.0))
            .bg(rgba(SEGMENT_BG))
            .text_size(px(12.0))
            .font_weight(FontWeight(500.0))
            .text_color(rgb(colors::INK_2))
            .cursor_pointer()
            .hover(|style| style.opacity(0.92))
            .active(|style| style.opacity(0.82))
            .on_click(cx.listener(|shell, _, window, cx| {
                shell.reset_appearance(window, cx);
            }))
            .child("Reset")
            .into_any_element(),
    )
}

fn settings_row(title: &'static str, detail: &'static str, control: AnyElement) -> AnyElement {
    div()
        .flex()
        .items_center()
        .gap(px(16.0))
        .py(px(14.0))
        .border_b_1()
        .border_color(rgba(colors::DIVIDER))
        .child(
            div()
                .flex_1()
                .min_w_0()
                .flex()
                .flex_col()
                .gap_1()
                .child(
                    div()
                        .text_size(px(13.0))
                        .font_weight(FontWeight(500.0))
                        .text_color(rgb(colors::INK))
                        .child(title),
                )
                .child(
                    div()
                        .text_size(px(11.5))
                        .text_color(rgb(colors::INK_3))
                        .child(detail),
                ),
        )
        .child(control)
        .into_any_element()
}

fn wallpaper_label(theme: WallpaperTheme) -> &'static str {
    match theme {
        WallpaperTheme::Dawn => "Dawn",
        WallpaperTheme::Violet => "Violet",
        WallpaperTheme::Mint => "Mint",
        WallpaperTheme::Slate => "Slate",
    }
}

fn swatch_colors(theme: WallpaperTheme) -> (Hsla, Hsla, u32) {
    match theme {
        WallpaperTheme::Dawn => (
            hsla(351.0 / 360.0, 1.0, 0.91, 0.95),
            hsla(228.0 / 360.0, 1.0, 0.86, 0.85),
            0xefe8e1,
        ),
        WallpaperTheme::Violet => (
            hsla(263.0 / 360.0, 1.0, 0.88, 0.95),
            hsla(33.0 / 360.0, 1.0, 0.87, 0.85),
            0xe9e2ee,
        ),
        WallpaperTheme::Mint => (
            hsla(146.0 / 360.0, 0.69, 0.85, 0.95),
            hsla(40.0 / 360.0, 1.0, 0.86, 0.85),
            0xe6ece2,
        ),
        WallpaperTheme::Slate => (
            hsla(218.0 / 360.0, 0.20, 0.85, 0.95),
            hsla(20.0 / 360.0, 0.0, 0.10, 0.40),
            0xd6dae3,
        ),
    }
}

fn transparent_like(color: Hsla) -> Hsla {
    hsla(color.h, color.s, color.l, 0.0)
}

const SEGMENT_BG: u32 = 0x281e140d;
