use druid::{
    kurbo::{BezPath, RoundedRect},
    piet::{PaintBrush, PietTextLayout, StrokeStyle, Text, TextLayoutBuilder},
    widget::{Label, LabelText},
    Color, Data, RenderContext, Widget, WidgetPod,
};
use crate::widgets::label;
pub struct MenuItem<D> {
    title: WidgetPod<D, Label<D>>,
    desc_text: Option<PietTextLayout>,
}
const LEFT_RIGHT_PADDING: f64 = 5.;
impl<D: Data> MenuItem<D> {
    pub fn new(title: impl Into<LabelText<D>>) -> Self {
        MenuItem {
            title: WidgetPod::new(label::new(title)),
            desc_text: None,
        }
    }
}
impl Widget<()> for MenuItem<()> {
    fn event(
        &mut self,
        _ctx: &mut druid::EventCtx,
        _event: &druid::Event,
        _data: &mut (),
        _env: &druid::Env,
    ) {
        todo!()
    }
    fn lifecycle(
        &mut self,
        _ctx: &mut druid::LifeCycleCtx,
        _event: &druid::LifeCycle,
        _data: &(),
        _env: &druid::Env,
    ) {
        todo!()
    }
    fn update(
        &mut self,
        _ctx: &mut druid::UpdateCtx,
        _old_data: &(),
        _data: &(),
        _env: &druid::Env,
    ) {
        todo!()
    }
    fn layout(
        &mut self,
        _ctx: &mut druid::LayoutCtx,
        _bc: &druid::BoxConstraints,
        _data: &(),
        _env: &druid::Env,
    ) -> druid::Size {
        todo!()
    }
    fn paint(&mut self, _ctx: &mut druid::PaintCtx, _data: &(), _env: &druid::Env) {
        todo!()
    }
}
impl Widget<bool> for MenuItem<bool> {
    fn event(
        &mut self,
        ctx: &mut druid::EventCtx,
        event: &druid::Event,
        data: &mut bool,
        env: &druid::Env,
    ) {
        if let druid::Event::MouseDown(e) = event {
            if e.buttons.contains(druid::MouseButton::Left) && !ctx.is_disabled() {
                *data = !*data;
                ctx.request_paint();
            }
        }
        self.title.event(ctx, event, data, env);
    }
    fn lifecycle(
        &mut self,
        ctx: &mut druid::LifeCycleCtx,
        event: &druid::LifeCycle,
        data: &bool,
        env: &druid::Env,
    ) {
        if let druid::LifeCycle::HotChanged(_) = event {
            ctx.request_paint();
        }
        if let druid::LifeCycle::FocusChanged(_) = event {
            ctx.request_paint();
        }
        self.title.lifecycle(ctx, event, data, env);
    }
    fn update(
        &mut self,
        ctx: &mut druid::UpdateCtx,
        _old_data: &bool,
        data: &bool,
        env: &druid::Env,
    ) {
        if ctx.env_key_changed(&crate::theme::color::base::LOW)
            || ctx.env_key_changed(&crate::theme::color::list::LIST_LOW)
        {
            ctx.request_paint();
        }
        self.title.update(ctx, data, env);
    }
    fn layout(
        &mut self,
        ctx: &mut druid::LayoutCtx,
        bc: &druid::BoxConstraints,
        data: &bool,
        env: &druid::Env,
    ) -> druid::Size {
        let _ = self.title.layout(ctx, bc, data, env);
        self.title
            .set_origin(ctx, (8. + LEFT_RIGHT_PADDING, 7.).into());
        bc.constrain((100., 32.))
    }
    fn paint(&mut self, ctx: &mut druid::PaintCtx, data: &bool, env: &druid::Env) {
        let is_active = ctx.is_active();
        let is_disabled = ctx.is_disabled();
        let r = ctx.size().to_rect();
        if ctx.is_hot() && !is_disabled {
            ctx.fill(
                r,
                &PaintBrush::Color(if is_active {
                    env.get(crate::theme::color::base::LOW)
                } else {
                    env.get(crate::theme::color::list::LIST_LOW)
                }),
            );
        }
        self.title.paint(ctx, data, env);
        if *data {
            let rr = RoundedRect::from_origin_size(
                (r.width() - 32. - LEFT_RIGHT_PADDING + 6.5, 6.5),
                (19., 19.),
                3.5,
            );
            ctx.stroke(
                rr,
                &PaintBrush::Color(env.get(crate::theme::color::main::SECONDARY)),
                1.,
            );
            let rr = RoundedRect::from_origin_size(
                (r.width() - 32. - LEFT_RIGHT_PADDING + 7., 7.),
                (18., 18.),
                3.,
            );
            ctx.fill(
                rr,
                &PaintBrush::Color(env.get(crate::theme::color::main::PRIMARY)),
            );
            let mut check_path = BezPath::new();
            check_path.move_to((r.width() - 32. - LEFT_RIGHT_PADDING + 11.5, 16.5));
            check_path.line_to((r.width() - 32. - LEFT_RIGHT_PADDING + 14.5, 19.5));
            check_path.line_to((r.width() - 32. - LEFT_RIGHT_PADDING + 20.5, 13.5));
            ctx.stroke_styled(
                &check_path,
                &PaintBrush::Color(Color::WHITE),
                1.,
                &StrokeStyle {
                    line_join: druid::piet::LineJoin::Round,
                    line_cap: druid::piet::LineCap::Round,
                    ..Default::default()
                },
            );
        } else {
            let srr = RoundedRect::from_origin_size(
                (r.width() - 32. - LEFT_RIGHT_PADDING + 6.5, 6.5),
                (19., 19.),
                3.,
            );
            let frr = RoundedRect::from_origin_size(
                (r.width() - 32. - LEFT_RIGHT_PADDING + 7., 7.),
                (18., 18.),
                3.,
            );
            if env.get(crate::theme::color::main::IS_DARK) {
                ctx.stroke(srr, &PaintBrush::Color(Color::WHITE.with_alpha(0.5442)), 1.);
                ctx.stroke(frr, &PaintBrush::Color(Color::BLACK.with_alpha(0.1)), 1.);
            } else {
                ctx.stroke(srr, &PaintBrush::Color(Color::BLACK.with_alpha(0.4458)), 1.);
                ctx.stroke(frr, &PaintBrush::Color(Color::BLACK.with_alpha(0.4458)), 1.);
            }
        }
    }
}
impl Widget<String> for MenuItem<String> {
    fn event(
        &mut self,
        ctx: &mut druid::EventCtx,
        event: &druid::Event,
        data: &mut String,
        env: &druid::Env,
    ) {
        self.title.event(ctx, event, data, env);
    }
    fn lifecycle(
        &mut self,
        ctx: &mut druid::LifeCycleCtx,
        event: &druid::LifeCycle,
        data: &String,
        env: &druid::Env,
    ) {
        if let druid::LifeCycle::HotChanged(_) = event {
            ctx.request_paint();
        }
        if let druid::LifeCycle::FocusChanged(_) = event {
            ctx.request_paint();
        }
        self.title.lifecycle(ctx, event, data, env);
    }
    fn update(
        &mut self,
        ctx: &mut druid::UpdateCtx,
        old_data: &String,
        data: &String,
        env: &druid::Env,
    ) {
        if !old_data.same(data) {
            self.desc_text = None;
            ctx.request_paint();
        }
        if ctx.env_key_changed(&crate::theme::color::base::MEDIUM)
            || ctx.env_key_changed(&crate::theme::color::typography::BODY)
        {
            ctx.request_paint();
        }
        if ctx.env_key_changed(&crate::theme::color::base::LOW)
            || ctx.env_key_changed(&crate::theme::color::list::LIST_LOW)
        {
            ctx.request_paint();
        }
        self.title.update(ctx, data, env);
    }
    fn layout(
        &mut self,
        ctx: &mut druid::LayoutCtx,
        bc: &druid::BoxConstraints,
        data: &String,
        env: &druid::Env,
    ) -> druid::Size {
        let _ = self.title.layout(ctx, bc, data, env);
        self.title
            .set_origin(ctx, (8. + LEFT_RIGHT_PADDING, 7.).into());
        self.desc_text = None;
        bc.constrain((100., 32.))
    }
    fn paint(&mut self, ctx: &mut druid::PaintCtx, data: &String, env: &druid::Env) {
        let is_active = ctx.is_active();
        let r = ctx.size().to_rect();
        if ctx.is_hot() {
            ctx.fill(
                r,
                &PaintBrush::Color(if is_active {
                    env.get(crate::theme::color::base::LOW)
                } else {
                    env.get(crate::theme::color::list::LIST_LOW)
                }),
            );
        }
        self.title.paint(ctx, data, env);
        if self.desc_text.is_none() {
            let font = env.get(crate::theme::color::typography::BODY);
            self.desc_text = Some(
                ctx.text()
                    .new_text_layout(data.to_owned())
                    .alignment(druid::TextAlignment::End)
                    .max_width(r.width() - 16.)
                    .font(font.family, 13.)
                    .text_color(env.get(crate::theme::color::base::MEDIUM))
                    .build()
                    .unwrap(),
            );
        }
        if data.is_empty() {
            let mut check_path = BezPath::new();
            check_path.move_to((r.width() - 32. - LEFT_RIGHT_PADDING + 14., 13.));
            check_path.line_to((r.width() - 32. - LEFT_RIGHT_PADDING + 17.5, 16.5));
            check_path.line_to((r.width() - 32. - LEFT_RIGHT_PADDING + 14., 20.));
            ctx.stroke_styled(
                &check_path,
                &PaintBrush::Color(Color::WHITE),
                1.,
                &StrokeStyle {
                    line_join: druid::piet::LineJoin::Round,
                    line_cap: druid::piet::LineCap::Round,
                    ..Default::default()
                },
            );
        } else if let Some(desc_text) = &self.desc_text {
            #[cfg(windows)]
            ctx.draw_text(desc_text, (0., 7.));
            #[cfg(not(windows))]
            {
                use druid::piet::TextLayout;
                ctx.draw_text(desc_text, (r.width() - 14. - desc_text.size().width, 7.))
            }
        }
    }
}