// SPDX-FileCopyrightText: 2024 vivi developers <vivi-ui@tuta.io>
// SPDX-License-Identifier: MIT

import { Border, BorderStyle, ScrollBarStyle, ScrollViewBase } from "../foundation.slint";
import { MagicPalette, MagicSizeSettings, MagicLayoutSettings, MagicAnimationSettings, MagicBorderSettings } from "./styling.slint";
import { StateLayer } from "state_layer.slint";

component ScrollBar {
    in property <bool> enabled <=> touch_area.enabled;
    in_out property <length> value;
    in property <length> maximum;
    in property <length> content_size;
    in property <ScrollBarStyle> style;
    in property <bool> horizontal;
    out property <bool> has_hover: touch_area.has_hover;

    property <length> offset: MagicLayoutSettings.control_spacing / 2;
    property <length> handle_padding: MagicLayoutSettings.control_spacing / 2;
    property <length> available_size: root.horizontal ? root.width - 2 * root.offset : root.height - 2 * offset;

    touch_area := TouchArea {
        property <length> pressed_value;

        pointer_event(event) => {
            if event.button == PointerEventButton.left && event.kind == PointerEventKind.down {
                self.pressed_value = -root.value;
            }
        }

        moved => {
            if !self.enabled || !self.pressed {
                return;
            }

            root.value = -max(0px, min(root.maximum, self.pressed_value + (
                 root.horizontal ? (self.mouse_x - self.pressed_x) * (root.maximum / (root.available_size - handle.width))
                                 : (self.mouse_y - self.pressed_y) * (root.maximum / (root.available_size - handle.height))
            )));
        }

        scroll_event(event) => {
            if root.horizontal && event.delta_x != 0 {
                root.value = max(-root.maximum, min(0px, root.value + event.delta_x));
                return accept;
            } else if !root.horizontal && event.delta_y != 0 {
                root.value = max(-root.maximum, min(0px, root.value + event.delta_y));
                return accept;
            }

            reject
        }
    }

    background_layer := Rectangle {
        background: transparent;
        border_width: 0;

        animate background { duration: MagicAnimationSettings.color_duration; }
    }

    border := Rectangle {
        x: 0;
        y: 0;
        width: root.horizontal ? root.width : root.style.border_style.border_width;
        height: root.horizontal ? root.style.border_style.border_width : root.height;
        background: root.style.border_style.border_brush;
        opacity: 0;

        animate background { duration: MagicAnimationSettings.color_duration; }
    }

    handle := Border {
        x: !root.horizontal ? (parent.width - self.width) / 2 : root.offset + (root.available_size - self.width) * (-root.value / root.maximum);
        y: root.horizontal ? (parent.height - self.height) / 2 : root.offset + (root.available_size - self.height) * (-root.value / root.maximum);
        width: !root.horizontal ? parent.width - 2 * root.handle_padding : root.maximum <= 0 ? 0 : max(MagicSizeSettings.control_height, root.available_size * (root.content_size / (root.maximum + root.content_size)));
        height: root.horizontal ? parent.height - 2 * root.handle_padding : root.maximum <= 0 ? 0 : max(MagicSizeSettings.control_height, root.available_size * (root.content_size / (root.maximum + root.content_size)));
        style: root.style.handle_style;
        border_radius: max(root.style.handle_style.border_radius, root.horizontal ? self.height / 2 : self.width / 2);
        opacity: 0.6;

        animate width, height { duration: MagicAnimationSettings.fast_resize_duration; }
    }

    state_layer := StateLayer {
        x: handle.x;
        y: handle.y;
        width: handle.width;
        height: handle.height;
        border_radius: handle.border_radius;
        pressed: touch_area.pressed;
        has_hover: touch_area.has_hover;
    }

    states [
        hover when touch_area.has_hover : {
            background_layer.background: root.style.border_style.background;
            handle_padding: MagicLayoutSettings.control_spacing;
            border.opacity: 1;
        }
    ]

    animate width, height, handle_padding { duration: MagicAnimationSettings.fast_resize_duration; }
}

export component ScrollView inherits ScrollViewBase {
    out property <length> visible_width <=> flickable.width;
    out property <length> visible_height <=> flickable.height;
    in_out property <bool> has_focus;

    min_width: 2 * MagicSizeSettings.control_height;
    min_height: self.min_width;
    preferred_width: 100%;
    preferred_height: 100%;
    viewport_x <=> flickable.viewport_x;
    viewport_y <=> flickable.viewport_y;
    viewport_width <=> flickable.viewport_width;
    viewport_height <=> flickable.viewport_height;
    style: {
        border_style: {
            background: MagicPalette.transparent,
        },
        scroll_bar_style: {
            border_style: {
                background: MagicPalette.foreground.with_alpha(0.2),
                border_width: MagicBorderSettings.control_border_width,
                border_brush: MagicPalette.border
            },
            handle_style: {
                background: MagicPalette.control_background,
                border_width: 0,
                border_brush: MagicPalette.transparent
            }
        }
    };

    flickable := Flickable {
        viewport_x <=> horizontal_scroll_bar.value;
        viewport_y <=> vertical_scroll_bar.value;

        @children
    }

    vertical_scroll_bar := ScrollBar {
        x: parent.width - self.width;
        y: 0;
        width: self.has_hover ? MagicSizeSettings.box_height : MagicSizeSettings.box_height / 2;
        height: horizontal_scroll_bar.visible ? parent.height - horizontal_scroll_bar.height : parent.height;
        style: root.style.scroll_bar_style;
        enabled: root.enabled;
        visible: flickable.viewport_height > flickable.height;
        maximum: flickable.viewport_height - flickable.height;
        content_size: flickable.height;
    }

    horizontal_scroll_bar := ScrollBar {
        x: 0;
        y: parent.height - self.height;
        width: vertical_scroll_bar.visible ? parent.width - vertical_scroll_bar.width : parent.width;
        height: self.has_hover ? MagicSizeSettings.box_height : MagicSizeSettings.box_height / 2;
        style: root.style.scroll_bar_style;
        enabled: root.enabled;
        visible: flickable.viewport_width > flickable.width;
        horizontal: true;
        maximum: flickable.viewport_width - flickable.width;
        content_size: flickable.width;
    }
}