#pragma once
#include <string>

#include "nodes.h"
#include <raylib/raylib.h>
namespace enginend::nodes::twod::relative {
	struct node2d :public node {
		double x;
		double y;
		double w;
		double h;
		node2d(){x=0;y=0;w=0;h=0;}
		node2d(double x,double y,double w=0,double h=0):x(x),y(y),w(w),h(h){}
	};
	struct rect :virtual public node2d{
		rect(){}
		rect(double x,double y,double w,double h):node2d(x,y,w,h){}
	};
	struct textured :virtual public rect{
		Texture2D* texture;
		textured(){texture=nullptr;}
		textured(Texture2D* texture,double x,double y,double w,double h):texture(texture),rect(x,y,w,h){}
		void boot() override{}
		void tick() override{}
		void draw()override{
			if(texture==nullptr)return;
			float sw=GetScreenWidth();
			float sh=GetScreenHeight();
			float ax=x*sw;
			float ay=y*sh;
			float aw=w*sw;
			float ah=h*sh;
			tiny::echo("og: %f %f %f %f", x,y,w,h);
			tiny::echo("transformed: %f %f %f %f", ax, ay, aw, ah);
			DrawTexturePro(*texture,{0,0,(float)texture->width,(float)texture->height},{ax,ay,aw,ah},{0,0},0,rl::WHITE);
		}
		void exit()override {
			if(texture){
				UnloadTexture(*texture);
				delete texture;
				texture=nullptr;
			}
		}
	};
	struct animated :virtual public textured{
		Image animimage;
		int frames;
		int currentframe;
		int framedelay;
		int framecounter;
		int prevframe;
		unsigned int nextframeoffset;
		animated():frames(0),currentframe(1),framedelay(6),framecounter(0),nextframeoffset(0){
			animimage.data=nullptr;
			prevframe=currentframe;
		}
		animated(const char* gifpath,double x,double y,double w,double h,int delay=6):
			textured(nullptr,x,y,w,h),framedelay(delay),currentframe(1),framecounter(0),frames(0),nextframeoffset(0)
		{
			prevframe=currentframe;
			this->x=x; this->y=y; this->w=w; this->h=h;
			animimage=LoadImageAnim(gifpath,&frames);
			if(frames>0){
				texture=new Texture2D(LoadTextureFromImage(animimage));
			}
		}
		void tick()override{
			if(frames<=1)return;
			framecounter++;
			if(framecounter>=framedelay){
				framecounter=0;
				currentframe++;
				if(currentframe>=frames)currentframe=0;
				nextframeoffset=animimage.width*animimage.height*4*currentframe;
				tiny::echo("updating node\nframes: %i\n current frame: %i",frames,currentframe);
				tiny::echo("%i",nextframeoffset);
			}
		}
		void draw()override {
			if (prevframe!=currentframe){
				prevframe=currentframe;
				UpdateTexture(*this->texture,((unsigned char*)animimage.data)+nextframeoffset);
			}
			textured::draw();
		}
		void exit()override{
			if(animimage.data)UnloadImage(animimage);
			textured::exit();
		}
	};
	struct colored :virtual public rect{
		Color c;
		colored(){}
		colored(Color color,double x,double y,double w,double h):c(color),rect(x,y,w,h){}
		void boot()override{}
		void tick()override{}
		void draw()override{
			float sw=GetScreenWidth();
			float sh=GetScreenHeight();
			float ax=x*sw;
			float ay=y*sh;
			float aw=w*sw;
			float ah=h*sh;
			DrawRectangle(ax,ay,aw,ah,c);
		}
		void exit()override{}
	};
	struct tinted :virtual public colored,virtual public textured{
		tinted(){}
		tinted(Texture2D* texture,Color color,double x,double y,double w,double h):
			node2d(x,y,w,h),
			rect(x,y,w,h),
			colored(color,x,y,w,h),
			textured(texture,x,y,w,h)
		{}
		void boot()override{}
		void tick()override{}
		void draw()override{
			if(texture==nullptr) {
				colored::draw();
				return;
			}
			float sw=GetScreenWidth();
			float sh=GetScreenHeight();
			float ax=x*sw;
			float ay=y*sh;
			float aw=w*sw;
			float ah=h*sh;
			DrawTexturePro(*texture,{0,0,(float)texture->width,(float)texture->height},{ax,ay,aw,ah},{0,0},0,c);
		}
		void exit()override{
			textured::exit();
		}
	};
	struct text :public tinted {
	protected:
		std::string result;
	public:
		float fs;
		std::string content;
		text(){fs=20;}
		text(Texture2D* texture,enginend::theme* theme,double x,double y,double w,double h,float fsize,std::string txt):
			//tinted(texture,color,x,y,w,h),
			fs(fsize),content(txt)
		{
			this->x=x;this->y=y;this->w=w;this->h=h;
			this->texture=texture;this->theme=theme;
			result=content;
			size_t initp=0;
			while((initp=result.find("\n",initp))!=std::string::npos){
				result.replace(initp,1,"\\n");
				initp+=2;
			}
		}
		void boot()override{}
		void tick()override {
			if(result!=content){
				result=content;
				size_t initp=0;
				while((initp=result.find("\n",initp))!=std::string::npos){
					result.replace(initp,1,"\\n");
					initp+=2;
				}
			}
		}
		void draw()override {
			float sw=GetScreenWidth();
			float sh=GetScreenHeight();
			float ax=x*sw;
			float ay=y*sh;
		
			float aw=w*sw;
			float ah=h*sh;
			tiny::echo("og: %f %f %f %f", x,y,w,h);
			tiny::echo("drawing text: %s", content.c_str());
			tiny::echo("transformed: %f %f %f %f", ax, ay, aw, ah);
			Vector2 minsize=MeasureTextEx(this->theme->font,content.c_str(),fs,1);
			Vector2 charsize=MeasureTextEx(this->theme->font," ",fs,1);
			float p=charsize.x>charsize.y?charsize.x/minsize.x:charsize.y/minsize.y;
			p=p*2;
			int minh=(minsize.y>ah)?minsize.y:ah;
			int minw=(minsize.x>aw)?minsize.x:aw;
			DrawRectangle(ax-charsize.x,ay-charsize.y,minw+p,minh+p,this->theme->background);
			DrawTextEx(this->theme->font,content.c_str(),{ax,ay},fs,1,this->theme->text);
			DrawRectangleLines(ax, ay, aw, ah, this->theme->border);
		}
		void exit()override{
			tinted::exit();
		}
	};
	struct button :virtual public tinted{
		std::function<void()> func;
		bool pressed;
		bool hover;
		const bool isboolean;
		bool boolean=false;
		button():func(nullptr),pressed(false),hover(false),isboolean(false){}
		button(Texture2D* texture,enginend::theme* theme,double x,double y,double w,double h,std::function<void()> f):func(f),pressed(false),hover(false),isboolean(false) {
			this->theme=theme;this->texture=texture;this->x=x;this->y=y;this->w=w;this->h=h;
		}button(Texture2D* texture,enginend::theme* theme,double x,double y,double w,double h,std::function<void()> f,bool isboolean):func(f),pressed(false),hover(false),isboolean(isboolean) {
			this->theme=theme;this->texture=texture;this->x=x;this->y=y;this->w=w;this->h=h;
		}
		void boot()override{}
		void tick()override{
		}
		void draw()override {
		
			Vector2 mouse=GetMousePosition();
			float sw=GetScreenWidth();
			float sh=GetScreenHeight();
			Rectangle r={float(x*sw),float(y*sh),float(w*sw),float(h*sh)};
			if(CheckCollisionPointRec(mouse,r)){hover=true;
				if(IsMouseButtonPressed(MOUSE_LEFT_BUTTON)){
					pressed=true;
					c=isboolean?boolean?
						this->theme->booleanbutton[5]:this->theme->booleanbutton[2]:
						this->theme->button[2];
					if(func)func();
				}else{
					pressed=false;
					c=isboolean?boolean?
						this->theme->booleanbutton[4]:this->theme->booleanbutton[1]:
						this->theme->button[1];
				}
			}else{
				hover=false;
				pressed=false;
				c=isboolean?boolean?
					this->theme->booleanbutton[3]:this->theme->booleanbutton[0]:
					this->theme->button[0];
			}
			float ax=x*sw;
			float ay=y*sh;
			float aw=w*sw;
			float ah=h*sh;
			DrawRectangle(ax,ay,aw,ah,c);
			DrawRectangleLines(ax, ay, aw, ah, this->theme->border);
		}
		void exit()override{
			tinted::exit();
		}
	};
	struct labeledbutton :virtual public button {
		std::string label;
		int fs;
		Color txc;
		labeledbutton(std::string name,Texture2D* texture,enginend::theme*theme,
			double x,double y,double w,double h,std::function<void()> f,int size):fs(size),label(name),
			button(texture,theme,x,y,w,h,f)
		{}
		labeledbutton(std::string name,Texture2D* texture,enginend::theme*theme,
			double x,double y,double w,double h,std::function<void()> f,
			int size,bool isboolean):fs(size),label(name),
			button(texture,theme,x,y,w,h,f,isboolean)
		{}
		void boot()override{}
		void tick()override{
			button::tick();
		}
		void draw()override{
			button::draw();
			float sw=GetScreenWidth();
			float sh=GetScreenHeight();
			float ax=x*sw;
			float ay=y*sh;
			float aw=w*sw;
			float ah=h*sh;
			tiny::echo("ax %f x %f sw %f",ax,x,sw);
			tiny::echo("ay %f y %f sh %f",ay,y,sh);
			tiny::echo("aw %f w %f sw %f",aw,w,sw);
			tiny::echo("ah %f h %f sh %f",ah,h,sh);
			Vector2 tsize=MeasureTextEx(this->theme->font,label.c_str(),fs,1);
			Vector2 tpos={
				ax+(aw-tsize.x)/2,
				ay+(ah-tsize.y)/2
			 };
			tiny::echo("tsize\nw %f h %f",tsize.x,tsize.y);
			tiny::echo("tpos\nx %f y %f",tpos.x,tpos.y);
			if (hover) {
				if (pressed) {
					txc=isboolean?boolean?
						this->theme->booleantext[5]:this->theme->booleantext[2]:
						this->theme->buttontext[2];
				}else {
					txc=isboolean?boolean?
						this->theme->booleantext[4]:this->theme->booleantext[1]:
						this->theme->buttontext[1];
				}
			}else {
				txc=isboolean?boolean?
					this->theme->booleantext[3]:this->theme->booleantext[0]:
					this->theme->buttontext[0];
			}
			DrawTextEx(this->theme->font,label.c_str(),tpos,fs,1,txc);
			DrawRectangleLinesEx({ax, ay, aw, ah},5., this->theme->border);
		}
		void exit()override{
			button::exit();
		}
	};
	struct slider :virtual public tinted{
		float val;
		float minv;
		float maxv;
		slider():val(0),minv(0),maxv(1){}
		slider(Texture2D* texture,Color color,double x,double y,double w,double h,float min,float max,float v):val(v),minv(min),maxv(max),tinted(texture,color,x,y,w,h){}
		void boot()override{}
		void tick()override{
			Vector2 mouse=GetMousePosition();
			float sw=GetScreenWidth();
			float sh=GetScreenHeight();
			Rectangle r={float(x*sw),float(y*sh),float(w*sw),float(h*sh)};
			if(CheckCollisionPointRec(mouse,r)&&IsMouseButtonDown(MOUSE_LEFT_BUTTON)){
				float t=(mouse.x-(x*sw))/(w*sw);
				val=minv+t*(maxv-minv);
				if(val<minv)val=minv;
				if(val>maxv)val=maxv;
			}
		}
		void draw()override{
			float sw=GetScreenWidth();
			float sh=GetScreenHeight();
			float ax=x*sw;
			float ay=y*sh;
			float aw=w*sw;
			float ah=h*sh;
			DrawRectangle(ax,ay,aw,ah,rl::DARKGRAY);
			float t=(val-minv)/(maxv-minv);
			DrawRectangle(ax,ay,aw*t,ah,c);
		}
		void exit()override{
			tinted::exit();
		}
	};
	struct textfield :public text{
		textfield(){}
		textfield(Texture2D* texture,enginend::theme *theme,double x,double y,double w,double h,float fsize,std::string txt):
			text(texture,theme,x,y,w,h,fsize,txt){}
		void boot()override{}
		void tick()override{
			text::tick();
		}
		void draw()override{
			float sw=GetScreenWidth();
			float sh=GetScreenHeight();
			float ax=x*sw;
			float ay=y*sh;
			float aw=w*sw;
			float ah=h*sh;
			Vector2 charsize=MeasureTextEx(this->theme->font," ",fs,0);
			Vector2 minsize=MeasureTextEx(this->theme->font,content.c_str(),fs,charsize.x/2);
			float po=charsize.x>charsize.y?charsize.x/charsize.y:charsize.y/charsize.x;po=po*5;
			int minh=(minsize.y>ah)?minsize.y:ah;
			int minw=(minsize.x>aw)?minsize.x:aw;
			DrawRectangle(ax-(po/2),ay-(po/2),minw+(po*1.1),minh+(po*1.1),this->theme->textfieldbg);
			DrawTextEx(this->theme->font,content.c_str(),{ax,ay},fs,charsize.x/2,this->theme->text);
		}
		void exit()override{
			text::exit();
		}
	};
	struct textinput :public text{
		bool active;
		int cpos;
		textinput():active(false),cpos(0){}
		textinput(Texture2D* texture,enginend::theme *theme,double x,double y,double w,double h,float fsize):active(false),cpos(0),
			text(texture,theme,x,y,w,h,fsize,""){}
		void boot()override{}
		void tick()override{
			text::tick();
			Vector2 mouse=GetMousePosition();
			float sw=GetScreenWidth();
			float sh=GetScreenHeight();
			Rectangle r={float(x*sw),float(y*sh),float(w*sw),float(h*sh)};
			if(IsMouseButtonPressed(MOUSE_LEFT_BUTTON)){
				active=CheckCollisionPointRec(mouse,r);
			}
			if(active){
				int key=GetCharPressed();
				while(key>0){
					if(key>=32&&key<=125){
						content+=static_cast<char>(key);
						cpos++;
					}
					key=GetCharPressed();
				}
				if(IsKeyPressed(KEY_BACKSPACE)&&content.length()>0){
					content.pop_back();
					cpos--;
				}
			}
		}
		void draw()override{
			text::draw();
			if(active){
				float sw=GetScreenWidth();
				float sh=GetScreenHeight();
				float ax=x*sw;
				float ay=y*sh;
				DrawRectangle(ax+MeasureTextEx(this->theme->font,content.c_str(),fs,1).x,ay,2,fs,{0,0,0,127});
			}
		}
		void exit()override{
			text::exit();
		}
	};
	struct textinputfield :public textfield{
		bool active;
		int cpos;
		textinputfield():active(false),cpos(0){}
		textinputfield(Texture2D* texture,enginend::theme *theme,double x,double y,double w,double h,float fsize):active(false),cpos(0),
			textfield(texture,theme,x,y,w,h,fsize,""){}
		void boot()override{}
		void tick()override{
			textfield::tick();
			Vector2 mouse=GetMousePosition();
			float sw=GetScreenWidth();
			float sh=GetScreenHeight();
			Rectangle r={float(x*sw),float(y*sh),float(w*sw),float(h*sh)};
			if(IsMouseButtonPressed(MOUSE_LEFT_BUTTON)){
				active=CheckCollisionPointRec(mouse,r);
			}
			if(active){
				int key=GetCharPressed();
				while(key>0){
					if(key>=32&&key<=125){
						content+=static_cast<char>(key);
						cpos++;
					}
					key=GetCharPressed();
				}
				if(IsKeyPressed(KEY_BACKSPACE)&&content.length()>0){
					content.pop_back();
					cpos--;
				}
				if(IsKeyPressed(KEY_ENTER)){
					content+='\n';
					cpos++;
				}
			}
		}
		void draw()override{
			textfield::draw();
			if(active){
				float sw=GetScreenWidth();
				float sh=GetScreenHeight();
				float ax=x*sw;
				float ay=y*sh;
				float lh=fs+2;
				Vector2 p={ax,ay};
				std::string line="";
				for(char ch:content){
					if(ch=='\n'){
						p.y+=lh;
						line="";
					}else{
						line+=ch;
					}
				}
				DrawRectangle(p.x+MeasureTextEx(this->theme->font,line.c_str(),fs,1).x,p.y,2,fs,rl::BLACK);
			}
		}
		void exit()override{
			textfield::exit();
		}
	};
}

