#pragma once
#include "Menu.h"
#include "MenuComponent.h"
#include "MenuItemButton.h"
#include "Crawler.h"

typedef Attribute A;

class ScrollableWindowComponent:public MenuComponent{
protected:
    Renderable r;
    std::vector<MenuComponent*>components;
    MenuComponent*upButton=nullptr;
    MenuComponent*downButton=nullptr;
    geom2d::rect<float>bounds; //It's for the scrollbar.
    float scrollBarHeight=0;
    float scrollBarTop=0;
    bool scrollBarSelected=false;
    float scrollBarHoverTime=0;
protected:
    inline bool OnScreen(MenuComponent*component){
        return geom2d::overlaps(geom2d::rect<float>{{},rect.size},geom2d::rect<float>{component->rect.pos+V(A::SCROLL_OFFSET)+vf2d{2,2},component->rect.size-vf2d{2,2}});
    }
public:
    inline ScrollableWindowComponent(MenuType parent,geom2d::rect<float>rect,ComponentAttr attributes=ComponentAttr::BACKGROUND|ComponentAttr::OUTLINE)
        :MenuComponent(parent,rect,"",[](MenuFuncData data){return true;},ButtonAttr::UNSELECTABLE|ButtonAttr::UNSELECTABLE_VIA_KEYBOARD){
        background=attributes&ComponentAttr::BACKGROUND;
        border=attributes&ComponentAttr::OUTLINE;
        r.Create(rect.size.x,rect.size.y);
    }
protected:
    virtual inline void AfterCreate()override{
        upButton=NEW MenuComponent(parentMenu,{rect.pos+vf2d{rect.size.x-12,0},{12,12}},"^",[&](MenuFuncData dat){V(A::SCROLL_OFFSET).y+="ThemeGlobal.MenuButtonScrollSpeed"_I;return true;},ButtonAttr::UNSELECTABLE_VIA_KEYBOARD);
        downButton=NEW MenuComponent(parentMenu,{rect.pos+rect.size-vf2d{12,12},{12,12}},"v",[&](MenuFuncData dat){V(A::SCROLL_OFFSET).y-="ThemeGlobal.MenuButtonScrollSpeed"_I;return true;},ButtonAttr::UNSELECTABLE_VIA_KEYBOARD);
        //Let's use the internal name of this component to add unique names for sub-components.
        Menu::menus[parentMenu]->AddComponent(name+upButton->rect.pos.str()+"_"+upButton->rect.size.str(),upButton); 
        Menu::menus[parentMenu]->AddComponent(name+downButton->rect.pos.str()+"_"+downButton->rect.size.str(),downButton);
    }
protected:
    virtual inline void Update(Crawler*game)override{
	    MenuComponent::Update(game);

        vf2d windowAbsPos=Menu::menus[parentMenu]->pos+rect.pos;

        bool mouseOverScrollbar=geom2d::overlaps(geom2d::rect<float>(windowAbsPos+vf2d{rect.size.x-12,scrollBarTop+12},{12,scrollBarHeight}),game->GetMousePos());

        if(mouseOverScrollbar||scrollBarSelected){
            scrollBarHoverTime=std::min(scrollBarHoverTime+game->GetElapsedTime(),"ThemeGlobal.HighlightTime"_F);
            if(game->GetMouse(0).bPressed){
                scrollBarSelected=true;
            }
            if(game->GetMouse(0).bReleased){
                scrollBarSelected=false;
            }
            if(scrollBarSelected){
                float spaceBetweenTopAndBottomArrows=rect.size.y-24;
                float viewHeight=rect.size.y;


                float totalContentHeight=bounds.size.y;
                if(totalContentHeight==0)totalContentHeight=1;
                float scrollBarScale=(spaceBetweenTopAndBottomArrows/totalContentHeight);
                //The scroll amount moves centered on the position the mouse is at.
                float newScrollbarTop=(game->GetMousePos().y-windowAbsPos.y-12)-scrollBarHeight/2;
                V(A::SCROLL_OFFSET).y=(-newScrollbarTop+1)/scrollBarScale; //Derived formula from the draw code.
            }
        }else{
            scrollBarHoverTime=std::max(scrollBarHoverTime-game->GetElapsedTime(),0.f);
        }

        if(game->GetMouseWheel()!=0){
            if(game->GetMouseWheel()>0){
                V(A::SCROLL_OFFSET).y+="ThemeGlobal.MenuScrollWheelSpeed"_I;
            }else{
                V(A::SCROLL_OFFSET).y-="ThemeGlobal.MenuScrollWheelSpeed"_I;
            }
        }

        if(bounds.size.y-rect.size.y>0){
            V(A::SCROLL_OFFSET).y=std::clamp(V(A::SCROLL_OFFSET).y,-(bounds.size.y-rect.size.y),0.f);
        }else{
            V(A::SCROLL_OFFSET).y=0;
        }

        for(MenuComponent*component:components){
            component->disabled=!OnScreen(component);
            component->_Update(game);
        }

        upButton->disabled=false;
        downButton->disabled=false;
        if(geom2d::contains(rect,bounds)){//This means we have no reason to show a scrollbar.
            upButton->disabled=true;
            downButton->disabled=true;
        }
    }
    virtual inline void Draw(Crawler*game,vf2d parentPos)override{
	    MenuComponent::Draw(game,parentPos);
        Sprite*prevDrawTarget=game->GetDrawTarget();
        game->SetDrawTarget(r.Sprite());
        game->Clear(BLANK);
        for(MenuComponent*component:components){
            component->_Draw(game,V(A::SCROLL_OFFSET));
        }
        game->SetDrawTarget(prevDrawTarget);
        game->DrawSprite(parentPos+rect.pos,r.Sprite());
    }

    inline void DrawScrollbar(Crawler*game,vf2d parentPos,bool focused){
        float spaceBetweenTopAndBottomArrows=rect.size.y-24;
        float viewHeight=rect.size.y;
        float totalContentHeight=bounds.size.y;
        if(totalContentHeight==0)totalContentHeight=1;
        float scrollBarScale=(spaceBetweenTopAndBottomArrows/totalContentHeight);
        scrollBarHeight=std::min(spaceBetweenTopAndBottomArrows,viewHeight*scrollBarScale-1);
        scrollBarTop=-V(A::SCROLL_OFFSET).y*scrollBarScale+1;

        float focusedWindowColorMult=(focused?1:"ThemeGlobal.MenuUnfocusedColorMult"_F);

        game->FillRectDecal(rect.pos+parentPos+vf2d{rect.size.x-11.75f,scrollBarTop+12},{12,scrollBarHeight},PixelLerp(Menu::GetCurrentTheme().GetButtonCol(),Menu::GetCurrentTheme().GetHighlightCol(),scrollBarHoverTime/"ThemeGlobal.HighlightTime"_F)*focusedWindowColorMult);
        game->DrawRectDecal(rect.pos+parentPos+vf2d{rect.size.x-11.75f,scrollBarTop+12},{12,scrollBarHeight},WHITE*focusedWindowColorMult);
    }

    virtual inline void DrawDecal(Crawler*game,vf2d parentPos,bool focused)override{
	    MenuComponent::DrawDecal(game,parentPos,focused);
        if(border){
            game->DrawRectDecal(rect.pos+Menu::menus[parentMenu]->pos,rect.size);
        }
        for(MenuComponent*component:components){
            component->_DrawDecal(game,rect.pos+Menu::menus[parentMenu]->pos+V(A::SCROLL_OFFSET),focused);
        }
        DrawScrollbar(game,Menu::menus[parentMenu]->pos,focused);
    }
    virtual bool GetHoverState(Crawler*game,MenuComponent*child)override{
		return geom2d::overlaps(geom2d::rect<float>{Menu::menus[parentMenu]->pos+rect.pos+child->rect.pos+V(A::SCROLL_OFFSET),child->rect.size},game->GetMousePos());
    }
    //Calculates the bounds of all components.
    geom2d::rect<float> inline CalculateBounds(){
        geom2d::rect<float>bounds;
        for(MenuComponent*component:components){
            if(component->rect.pos.x<bounds.pos.x){
                float sizeIncrease=bounds.pos.x-component->rect.pos.x;
                bounds.size.x+=sizeIncrease;
                bounds.pos.x=component->rect.pos.x;
            }
            if(component->rect.right().start.x>bounds.right().start.x){
                float sizeIncrease=component->rect.right().start.x-bounds.right().start.x;
                bounds.size.x+=sizeIncrease;
            }
            if(component->rect.pos.y<bounds.pos.y){
                float sizeIncrease=bounds.pos.y-component->rect.pos.y;
                bounds.size.y+=sizeIncrease;
                bounds.pos.y=component->rect.pos.y;
            }
            if(component->rect.bottom().start.y>bounds.bottom().start.y){
                float sizeIncrease=component->rect.bottom().start.y-bounds.bottom().start.y;
                bounds.size.y+=sizeIncrease;
            }
        }
        return bounds;
    }
public:
    void inline AddComponent(Menu*parentMenu,std::string key,MenuComponent*button){
        components.push_back(button);
        button->renderInMain=false; //Now we are in control!
        button->parentComponent=this;

        if(button->rect.pos.x<bounds.pos.x){
            float sizeIncrease=bounds.pos.x-button->rect.pos.x;
            bounds.size.x+=sizeIncrease;
            bounds.pos.x=button->rect.pos.x;
        }
        if(button->rect.right().start.x>bounds.right().start.x){
            float sizeIncrease=button->rect.right().start.x-bounds.right().start.x;
            bounds.size.x+=sizeIncrease;
        }
        if(button->rect.pos.y<bounds.pos.y){
            float sizeIncrease=bounds.pos.y-button->rect.pos.y;
            bounds.size.y+=sizeIncrease;
            bounds.pos.y=button->rect.pos.y;
        }
        if(button->rect.bottom().start.y>bounds.bottom().start.y){
            float sizeIncrease=button->rect.bottom().start.y-bounds.bottom().start.y;
            bounds.size.y+=sizeIncrease;
        }

        parentMenu->AddComponent(key,button);
    }
    virtual inline bool PointWithinParent(MenuComponent*child,vi2d drawPos)override{
        return geom2d::overlaps(geom2d::rect<float>{Menu::menus[parentMenu]->pos+rect.pos,rect.size},drawPos);
    }
    virtual inline bool HandleOutsideDisabledButtonSelection(MenuComponent*disabledButton)override{
        //Set the offset so the center is highlighted by this button.
        V(A::SCROLL_OFFSET).y=-(disabledButton->rect.pos.y-disabledButton->rect.size.y/2);
        V(A::SCROLL_OFFSET).y+=rect.size.y/2;
        return true;
    };
    virtual void Cleanup()override{}
};