use macroquad::prelude::*;

pub fn xbutton(x: f32, y: f32, text: String) -> (bool, f32){
    let (mousex, mousey) = mouse_position();

    if mousex >= x && mousey >= y && mousex <=  x + (text.len() as f32 *7.0 + 8.0) && mousey <= y + 18.0 && is_mouse_button_down(MouseButton::Left) {
        //button held down / clicked
        draw_rectangle(x, y, text.len() as f32 *7.0 + 8.0, 18.0, WHITE);
        draw_rectangle(x, y, text.len() as f32 *7.0 + 7.0, 17.0, GRAY);
        draw_line(x, y+1.0, x + text.len() as f32 *7.0 + 7.0, y, 1.0, DARKGRAY);
        draw_line(x+1.0, y, x+1.0, y + 17.0, 1.0, DARKGRAY);
        draw_rectangle(x+1.0, y+1.0, text.len() as f32 *7.0 + 5.0, 15.0, Color::new(0.6, 0.6, 0.6, 1.0));
        draw_text(&text, x+2.0, y+12.0, 16.0, BLACK);
        return (true, text.len() as f32 *7.0 + 8.0);
        //returns the button width for use in spacing and that the button was pressed
    }else{
        //button not clicked (up state)
        draw_rectangle(x, y, text.len() as f32 *7.0 + 8.0, 18.0, DARKGRAY);
        draw_rectangle(x, y, text.len() as f32 *7.0 + 7.0, 17.0, GRAY);
        draw_line(x, y+1.0, x + text.len() as f32 *7.0 + 7.0, y, 1.0, WHITE);
        draw_line(x+1.0, y, x+1.0, y + 17.0, 1.0, WHITE);
        draw_rectangle(x+1.0, y+1.0, text.len() as f32 *7.0 + 5.0, 15.0, LIGHTGRAY);
        draw_text(&text, x+2.0, y+12.0, 16.0, BLACK);
        return (false, text.len() as f32 *7.0 + 8.0);
        //returns the button width for use in spacing and that the button was not pressed
    }
}

pub fn xtogglebutton(x: f32, y: f32, text: String, mut state: bool) -> (bool, f32){
    let (mousex, mousey) = mouse_position();//get mouse pos
    //if clicked invert the button's state
    if mousex >= x && mousey >= y && mousex <=  x + (text.len() as f32 *7.0 + 8.0) && mousey <= y + 18.0 && is_mouse_button_pressed(MouseButton::Left){
        state = !state;
    }
    if state{
        //draw button down
        draw_rectangle(x, y, text.len() as f32 *7.0 + 8.0, 18.0, WHITE);
        draw_rectangle(x, y, text.len() as f32 *7.0 + 7.0, 17.0, GRAY);
        draw_line(x, y+1.0, x + text.len() as f32 *7.0 + 7.0, y, 1.0, DARKGRAY);
        draw_line(x+1.0, y, x+1.0, y + 17.0, 1.0, DARKGRAY);
        draw_rectangle(x+1.0, y+1.0, text.len() as f32 *7.0 + 5.0, 15.0, Color::new(0.6, 0.6, 0.6, 1.0));
        draw_text(&text, x+2.0, y+12.0, 16.0, BLACK);
        return (state, text.len() as f32 *7.0 + 8.0);
        //returns the button width for use in spacing and that the button was pressed
    }else{
        //else - draw button up
        draw_rectangle(x, y, text.len() as f32 *7.0 + 8.0, 18.0, DARKGRAY);
        draw_rectangle(x, y, text.len() as f32 *7.0 + 7.0, 17.0, GRAY);
        draw_line(x, y+1.0, x + text.len() as f32 *7.0 + 7.0, y, 1.0, WHITE);
        draw_line(x+1.0, y, x+1.0, y + 17.0, 1.0, WHITE);
        draw_rectangle(x+1.0, y+1.0, text.len() as f32 *7.0 + 5.0, 15.0, LIGHTGRAY);
        draw_text(&text, x+2.0, y+12.0, 16.0, BLACK);
        return (false, text.len() as f32 *7.0 + 8.0);
        //returns the button width for use in spacing and that the button was not pressed
    }
}

pub fn xcheckbox(x: f32, y: f32, state: bool) -> bool{
    let (mousex, mousey) = mouse_position();//get mouse pos
    //draw rectangle
    draw_rectangle(x, y, 15.0, 15.0, WHITE);
    draw_rectangle(x, y, 15.0, 15.0, GRAY);
    draw_rectangle(x+1.0, y+1.0, 13.0, 13.0, DARKGRAY);
    draw_rectangle(x+2.0, y+2.0, 12.0, 12.0, LIGHTGRAY);
    draw_rectangle(x+2.0, y+2.0, 11.0, 11.0, WHITE);
    draw_line(x+15.0, y+1.0, x+15.0, y + 15.0, 1.0, WHITE);
    draw_line(x+1.0, y+15.0, x+15.0, y + 15.0, 1.0, WHITE);
    if state == true{
        //if the checkbox is in the checked state draw the tick
        draw_line(x+5.0, y+10.0, x+8.0, y + 13.0, 2.0, LIGHTGRAY);
        draw_line(x+8.0, y+13.0, x+12.0, y + 4.0, 2.0, LIGHTGRAY);
        draw_line(x+4.0, y+9.0, x+7.0, y + 12.0, 2.0, BLACK);
        draw_line(x+7.0, y+12.0, x+11.0, y + 3.0, 2.0, BLACK);
    }
    if mousex >= x && mousey >= y && mousex <=  x + 14.0 && mousey <= y + 14.0 && is_mouse_button_pressed(MouseButton::Left) {
        return !state;

    }else{
        return state;
    }
}

pub fn xloadbarblocks(x: f32, y: f32, width: f32, percentage: u8){
    //draw background rectangle
    draw_rectangle(x, y, width, 18.0, WHITE);
    draw_rectangle(x, y, width-1.0, 17.0, GRAY);
    draw_rectangle(x+1.0, y+1.0, width-2.0, 16.0, LIGHTGRAY);
    //iterate over percentage divided into 6px wide blocks
    for i in 0..(percentage as f32 / 100.0 * width / 6.0) as u32{
        draw_rectangle(x + (i * 6) as f32+2.0, y+2.0, 5.0, 14.0, BLUE)//draw 5px wide squares
    }
    draw_rectangle(x+width/2.0-8.0, y+3.0, 23.0, 12.0, LIGHTGRAY);
    draw_text(percentage.to_string().to_owned() + "%", x+width/2.0-8.0, y+13.0, 16.0, BLACK);
}

pub fn xlist(x: f32, y:f32, width:f32, height:f32, contents:&Vec<&str>, mut scroll:u32) -> u32{
    //draw list box
    draw_rectangle(x, y, width, height, GRAY);
    draw_rectangle(x+1.0, y+1.0, width-2.0, height-2.0, DARKGRAY);
    draw_rectangle(x+2.0, y+2.0, width-3.0, height-3.0, LIGHTGRAY);
    draw_rectangle(x+2.0, y+2.0, width-4.0, height-4.0, WHITE);
    draw_line(x+width, y+height, x+width, y+1.0, 1.0, WHITE);
    draw_line(x+width, y+height, x+1.0, y+height, 1.0, WHITE);

    //draw text with scroll offset
    if height as u32/13+scroll <= contents.len() as u32{//make sure we read data that exists
        for i in scroll..height as u32/13+scroll{//iterate over
            if contents[i as usize].len() >= (width/7.0) as usize{//crop if too wide
                draw_text(&contents[i as usize][0..(width/7.0 -2.0) as usize], x+3.0, y+3.0+i as f32*13.0+13.0-scroll as f32*13.0, 16.0, BLACK);//draw cropped
            }else{
                draw_text(&contents[i as usize], x+3.0, y+3.0+i as f32*13.0+13.0-scroll as f32*13.0, 16.0, BLACK);//draw not cropped for shorter ones (done to prevent loading stuff that ain't there)
            }
        }
    }else{
        for i in scroll..contents.len() as u32{
            if contents[i as usize].len() >= (width/7.0) as usize{
                draw_text(&contents[i as usize][0..(width/7.0 -2.0) as usize], x+3.0, y+3.0+i as f32*13.0+13.0-scroll as f32*13.0, 16.0, BLACK);
            }else{
                draw_text(&contents[i as usize], x+3.0, y+3.0+i as f32*13.0+13.0-scroll as f32*13.0, 16.0, BLACK);

            }
        }
    }
    //scroll area
    let mut sx = 0;
    draw_rectangle(x + width - 18.0, y + 2.0, 16.0, height - 5.0, LIGHTGRAY);
    for sx in 0..8{
        for i in 0..height as u32 / 2 - 5{
            draw_rectangle(x + width - 18.0 + sx as f32 * 2.0, y + 2.0+i as f32 * 2.0, 1.0, 1.0, WHITE);
        }
        for i in 0..height as u32 / 2 - 5{
            draw_rectangle(x + width - 17.0 + sx as f32 * 2.0, y + 3.0+i as f32 * 2.0, 1.0, 1.0, WHITE);
        }
    }
    //down button
    draw_rectangle(x + width - 18.0, y + height - 18.0, 16.0, 16.0, DARKGRAY);
    draw_rectangle(x + width - 18.0, y + height - 18.0, 15.0, 15.0, LIGHTGRAY);
    draw_rectangle(x + width - 17.0, y + height - 17.0, 14.0, 14.0, GRAY);
    draw_rectangle(x + width - 17.0, y + height - 17.0, 13.0, 13.0, WHITE);
    draw_rectangle(x + width - 16.0, y + height - 16.0, 12.0, 12.0, LIGHTGRAY);
    //lil black arrow
    draw_line(x + width - 14.0, y + height - 12.0, x + width - 10.0, y + height - 8.0, 1.0, BLACK);
    draw_line(x + width - 10.0, y + height - 8.0, x + width - 6.0, y + height - 12.0, 1.0, BLACK);
    draw_line(x + width - 13.0, y + height - 11.0, x + width - 7.0, y + height - 11.0, 2.0, BLACK);
    draw_line(x + width - 12.0, y + height - 9.0, x + width - 8.0, y + height - 9.0, 1.0, BLACK);

    //up button
    draw_rectangle(x + width - 18.0, y + 2.0, 16.0, 16.0, DARKGRAY);
    draw_rectangle(x + width - 18.0, y + 2.0, 15.0, 15.0, LIGHTGRAY);
    draw_rectangle(x + width - 17.0, y + 3.0, 14.0, 14.0, GRAY);
    draw_rectangle(x + width - 17.0, y + 3.0, 13.0, 13.0, WHITE);
    draw_rectangle(x + width - 16.0, y + 4.0, 12.0, 12.0, LIGHTGRAY);
    //lil black arrow (up edition)
    draw_line(x + width - 14.0, y + 20.0 - 8.0 ,x + width -10.0, y + 20.0 - 12.0,1.0, BLACK);
    draw_line(x + width - 10.0, y + 20.0 - 12.0,x + width - 6.0, y + 20.0 - 8.0 ,1.0, BLACK);
    draw_line(x + width - 14.0, y + 20.0 - 8.0 ,x + width - 6.0, y + 20.0 - 8.0 ,1.0, BLACK);
    draw_line(x + width - 12.0, y + 20.0 - 10.0,x + width - 8.0, y + 20.0 - 10.0 ,2.0, BLACK);

    let scrollheight = height - 38.0;//calculate height of scrollbar area
    //draw the scroll block bar thing
    draw_rectangle(x + width - 18.0, y + scrollheight/contents.len() as f32*scroll as f32 + 18.0, 16.0, 7.0, DARKGRAY);
    draw_rectangle(x + width - 18.0, y + scrollheight/contents.len() as f32*scroll as f32 + 18.0, 15.0, 6.0, WHITE);
    draw_rectangle(x + width - 17.0, y + scrollheight/contents.len() as f32*scroll as f32 + 19.0, 14.0, 5.0, GRAY);
    draw_rectangle(x + width - 17.0, y + scrollheight/contents.len() as f32*scroll as f32 + 19.0, 13.0, 4.0, LIGHTGRAY);
    //if mouse is down on scrollbar
    if down(x+width-18.0, y+18.0, 16.0, scrollheight){
        scroll = (mouse_position().1 - y - 18.0) as u32 / (scrollheight as u32/ contents.len() as u32);//calculate scroll from mouse pos
        if scroll > contents.len() as u32 -2{//if it's too big reduce by 1
            scroll -= 1;
        }
    }
    //if down button is clicked scroll down by 1 line
    if click(x + width - 18.0, y + height - 18.0, 16.0, 16.0){
        if !(scroll > contents.len() as u32 -2){
            scroll +=1;
        }
    }
    if click(x + width - 18.0, y+2.0, 16.0, 16.0){
        if !(scroll <= 0){
            scroll -=1;
        }
    }

    return scroll;

}

pub fn click(x: f32, y:f32, width:f32, height:f32) -> bool{
    let (mousex, mousey) = mouse_position();//get mouse pos
    //draw_rectangle(x, y, width, height, RED);//uncomment for debug square of clickable region
    if mousex >= x && mousey >= y && mousex <=  x + width && mousey <= y + height && is_mouse_button_pressed(MouseButton::Left) {//if mouse is in clickable area and down
        return true;//return true if it is
    }else{
        return false;//and return false if not :(
    }
}
pub fn down(x: f32, y:f32, width:f32, height:f32) -> bool{
    let (mousex, mousey) = mouse_position();//get mouse pos
    //draw_rectangle(x, y, width, height, RED);//uncomment for debug square of clickable region
    if mousex >= x && mousey >= y && mousex <=  x + width && mousey <= y + height && is_mouse_button_down(MouseButton::Left) {//if mouse is in clickable area and down
        return true;//return true if it is
    }else{
        return false;//and return false if not :(
    }
}
pub fn hover(x: f32, y:f32, width:f32, height:f32) -> bool{
    let (mousex, mousey) = mouse_position();//get mouse pos
    //draw_rectangle(x, y, width, height, RED);//uncomment for debug square of clickable region
    if mousex >= x && mousey >= y && mousex <=  x + width && mousey <= y + height{//if mouse is in clickable area
        return true;//return true if it is
    }else{
        return false;//and return false if not :(
    }
}

pub fn xhslider(x:f32, y:f32, width:f32, mut value:f32) -> f32{
    //draw slider track
    draw_rectangle(x, y+6.0, width, 1.0, GRAY);
    draw_rectangle(x, y+7.0, width, 1.0, DARKGRAY);
    draw_rectangle(x, y+9.0, width, 1.0, WHITE);

    //draw knob
    draw_rectangle(value * width - 3.5 + x, y, 8.0, 16.0, DARKGRAY);
    draw_rectangle(value * width - 3.5 + x, y, 7.0, 15.0, WHITE);
    draw_rectangle(value * width - 2.5 + x, y+1.0, 6.0, 14.0, GRAY);
    draw_rectangle(value * width - 2.5 + x, y+1.0, 5.0, 13.0, LIGHTGRAY);

    //get mouse x and convert to 0.0 - 1.0 range for slider
    if down(x-10.0, y, width+10.0, 16.0){
        value = (mouse_position().0 - x+1.0) / width;
        if value <= 0.0{
            value = 0.0;
        }
        if value >= 1.0{
            value = 1.0;
        }
    }
    return value;
}

pub fn xvslider(x:f32, y:f32, width:f32, mut value:f32) -> f32{
    //draw slider track
    draw_rectangle(x+6.0, y, 1.0, width, GRAY);
    draw_rectangle(x+7.0, y, 1.0, width, DARKGRAY);
    draw_rectangle(x+9.0, y, 1.0, width, WHITE);

    //draw slider knob (badly converted from hslider)
    draw_rectangle( x    ,value * width - 3.5 + y, 16.0,8.0 , DARKGRAY);
    draw_rectangle( x    ,value * width - 3.5 + y, 15.0,7.0 , WHITE);
    draw_rectangle( x+1.0,value * width - 2.5 + y, 14.0, 6.0, GRAY);
    draw_rectangle( x+1.0,value * width - 2.5 + y, 13.0, 5.0, LIGHTGRAY);
    //convert mouse y into 0.0 - 1.0 range for slider
    if down(x, y-10.0, 16.0, width+10.0){
        value = (mouse_position().1 - y+1.0) / width;
        if value <= 0.0{
            value = 0.0;
        }
        if value >= 1.0{
            value = 1.0;
        }
    }
    return value;
}

pub fn xinputbox(x:f32, y:f32, width:f32, height:f32, mut text:String) -> String{
    //bg box (stolen from list)
    draw_rectangle(x, y, width, height, GRAY);
    draw_rectangle(x+1.0, y+1.0, width-2.0, height-2.0, DARKGRAY);
    draw_rectangle(x+2.0, y+2.0, width-3.0, height-3.0, LIGHTGRAY);
    draw_rectangle(x+2.0, y+2.0, width-4.0, height-4.0, WHITE);
    draw_line(x+width, y+height, x+width, y+1.0, 1.0, WHITE);
    draw_line(x+width, y+height, x+1.0, y+height, 1.0, WHITE);

    if text.len() >= (width / 7.0) as usize{
        draw_text(&text[0..width as usize / 7 ], x+3.0, y+16.0, 16.0, BLACK);//cropped text
        //bad, really bad
        if text.len() >= (width / 7.0) as usize{
            if text.len() >= (width / 7.0) as usize*2{
                draw_text(&text[width as usize/ 7..width as usize/ 7*2], x+3.0, y+32.0, 16.0, BLACK);//ct ln 2
                if text.len() >= (width / 7.0) as usize*3{
                    draw_text(&text[width as usize/ 7*2..width as usize/ 7*3], x+3.0, y+48.0, 16.0, BLACK);//ct ln 3
                    draw_text(&text[width as usize/ 7*3..text.len()], x+3.0, y+64.0, 16.0, BLACK);//ct ln 4
                }else{
                    draw_text(&text[width as usize/ 7..text.len()as usize], x+3.0, y+32.0, 16.0, BLACK);//ct ln 2
                }
            }else{
                draw_text(&text[width as usize/ 7..text.len()as usize], x+3.0, y+32.0, 16.0, BLACK);//ct ln 2
            }
        }

    }else{
        draw_text(&text, x+3.0, y+16.0, 16.0, BLACK);//not cropped text
        //lil_cursor, only drawn if not past edge of box
        draw_rectangle(x+text.len() as f32*7.0+5.0, y+7.0, 1.0, 11.0, BLACK);
    }
    if hover(x, y, width, height){
        for i in get_keys_pressed(){//just puts the current char in i
            if i == KeyCode::Backspace{//if backspace is pressed delete the last char in the string
                if text.len() != 0{
                    text = text[0..text.len() - 1].to_string();
                }
            }else{
                //really, really bad this blocks any key you could press that could give an error
                if !(i == KeyCode::World1
                    || i == KeyCode::World2
                    || i == KeyCode::Escape
                    || i == KeyCode::Enter
                    || i == KeyCode::Tab
                    || i == KeyCode::Backspace
                    || i == KeyCode::Insert
                    || i == KeyCode::Delete
                    || i == KeyCode::Right
                    || i == KeyCode::Left
                    || i == KeyCode::Down
                    || i == KeyCode::Up
                    || i == KeyCode::PageUp
                    || i == KeyCode::PageDown
                    || i == KeyCode::Home
                    || i == KeyCode::End
                    || i == KeyCode::CapsLock
                    || i == KeyCode::ScrollLock
                    || i == KeyCode::NumLock
                    || i == KeyCode::PrintScreen
                    || i == KeyCode::Pause
                    || i == KeyCode::F1
                    || i == KeyCode::F2
                    || i == KeyCode::F3
                    || i == KeyCode::F4
                    || i == KeyCode::F5
                    || i == KeyCode::F6
                    || i == KeyCode::F7
                    || i == KeyCode::F8
                    || i == KeyCode::F9
                    || i == KeyCode::F10
                    || i == KeyCode::F11
                    || i == KeyCode::F12
                    || i == KeyCode::F13
                    || i == KeyCode::F14
                    || i == KeyCode::F15
                    || i == KeyCode::F16
                    || i == KeyCode::F17
                    || i == KeyCode::F18
                    || i == KeyCode::F19
                    || i == KeyCode::F20
                    || i == KeyCode::F21
                    || i == KeyCode::F22
                    || i == KeyCode::F23
                    || i == KeyCode::F24
                    || i == KeyCode::F25
                    || i == KeyCode::Kp0
                    || i == KeyCode::Kp1
                    || i == KeyCode::Kp2
                    || i == KeyCode::Kp3
                    || i == KeyCode::Kp4
                    || i == KeyCode::Kp5
                    || i == KeyCode::Kp6
                    || i == KeyCode::Kp7
                    || i == KeyCode::Kp8
                    || i == KeyCode::Kp9
                    || i == KeyCode::KpDecimal
                    || i == KeyCode::KpDivide
                    || i == KeyCode::KpMultiply
                    || i == KeyCode::KpSubtract
                    || i == KeyCode::KpAdd
                    || i == KeyCode::KpEnter
                    || i == KeyCode::KpEqual
                    || i == KeyCode::LeftShift
                    || i == KeyCode::LeftControl
                    || i == KeyCode::LeftAlt
                    || i == KeyCode::LeftSuper
                    || i == KeyCode::RightShift
                    || i == KeyCode::RightControl
                    || i == KeyCode::RightAlt
                    || i == KeyCode::RightSuper
                    || i == KeyCode::Menu
                    || i == KeyCode::Back
                    || i == KeyCode::Unknown
                ){
                    text = text + &(char::from_u32(i as u32)).expect("dats not rite").to_string() as &str
                }
            }
        }}
    println!("{text}");
    return text;

}
