/*
Copyright 2024, Savanni D'Gerinel <savanni@luminescent-dreams.com>

This file is part of On the Grid.

On the Grid is free software: you can redistribute it and/or modify it under the terms of
the GNU General Public License as published by the Free Software Foundation, either version 3 of
the License, or (at your option) any later version.

On the Grid is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License along with On the Grid. If not, see <https://www.gnu.org/licenses/>.
*/

use cairo::Context;
use gtk::prelude::*;
use otg_core::GameReviewViewModel;

const WIDTH: i32 = 200;
const HEIGHT: i32 = 800;

const RADIUS: f64 = 7.5;
const HIGHLIGHT_WIDTH: f64 = 4.;
const SPACING: f64 = 30.;

#[derive(Clone)]
pub struct ReviewTree {
    widget: gtk::ScrolledWindow,
    drawing_area: gtk::DrawingArea,

    view: GameReviewViewModel,
}

impl ReviewTree {
    pub fn new(view: GameReviewViewModel) -> ReviewTree {
        let drawing_area = gtk::DrawingArea::new();
        let widget = gtk::ScrolledWindow::builder().child(&drawing_area).build();

        widget.set_width_request(WIDTH);
        widget.set_height_request(HEIGHT);

        // TODO: figure out the maximum width of the tree so that we can also set a width request
        drawing_area.set_height_request(view.tree_max_depth() as i32 * SPACING as i32);

        let s = Self {
            widget,
            drawing_area,
            view,
        };

        s.drawing_area.set_draw_func({
            let s = s.clone();
            move |_, ctx, width, height| {
                s.redraw(ctx, width, height);
            }
        });

        s
    }

    pub fn queue_draw(&self) {
        self.drawing_area.queue_draw();
    }

    fn redraw(&self, ctx: &Context, _width: i32, _height: i32) {
        #[allow(deprecated)]
        let context = WidgetExt::style_context(&self.widget);
        #[allow(deprecated)]
        let foreground_color = context.lookup_color("sidebar_fg_color").unwrap();
        #[allow(deprecated)]
        let accent_color = context.lookup_color("accent_color").unwrap();

        self.view.map_tree(move |node, current| {
            let parent = node.parent();
            ctx.set_source_rgb(
                foreground_color.red().into(),
                foreground_color.green().into(),
                foreground_color.blue().into(),
            );
            let (row, column) = node.data().position();
            let y = (row as f64) * SPACING + RADIUS * 2.;
            let x = (column as f64) * SPACING + RADIUS * 2.;
            ctx.arc(x, y, RADIUS, 0., 2. * std::f64::consts::PI);
            let _ = ctx.fill();

            if let Some(parent) = parent {
                ctx.set_line_width(1.);
                let (row, column) = parent.data().position();
                let py = (row as f64) * SPACING + RADIUS * 2.;
                let px = (column as f64) * SPACING + RADIUS * 2.;
                ctx.move_to(px, py);
                ctx.line_to(x, y);
                let _ = ctx.stroke();
            }

            if current == Some(node.data().game_node_id) {
                ctx.set_line_width(HIGHLIGHT_WIDTH);
                ctx.set_source_rgb(
                    accent_color.red().into(),
                    accent_color.green().into(),
                    accent_color.blue().into(),
                );
                ctx.arc(
                    x,
                    y,
                    RADIUS + HIGHLIGHT_WIDTH / 2.,
                    0.,
                    2. * std::f64::consts::PI,
                );
                let _ = ctx.stroke();
                ctx.set_line_width(2.);
            }
        });
    }

    pub fn widget(&self) -> gtk::Widget {
        self.widget.clone().upcast::<gtk::Widget>()
    }
}

