use std::{thread, time::Duration};

use base64::prelude::*;
use maud::{Markup, PreEscaped, html};
use serde::Serialize;
use tao::{
    event::Event,
    event_loop::{ControlFlow, EventLoopBuilder},
    platform::unix::WindowExtUnix,
    window::{Fullscreen, WindowBuilder},
};
use wry::{WebViewBuilder, WebViewBuilderExtUnix};

static STYLESHEET: &str = include_str!("stylesheet.css");
static SCRIPT: &str = include_str!("app.js");
static RALEWAY: &[u8] = include_bytes!("Raleway.ttf");
static RALEWAY_ITALIC: &[u8] = include_bytes!("Raleway-Italic.ttf");
static ALBUM_COVER_1: &[u8] = include_bytes!("album01.jpg");
static ALBUM_COVER_2: &[u8] = include_bytes!("album02.jpg");

#[derive(Debug, Serialize)]
#[serde(untagged)]
enum JukeboxEvent {
    ShowPlaying {
        cover: String,
        title: String,
        artist: String,
        album: String,
    },
    RemovePlaying,
}

impl JukeboxEvent {
    fn get_invocation_name(&self) -> &'static str {
        match self {
            JukeboxEvent::ShowPlaying { .. } => "showPlaying",
            JukeboxEvent::RemovePlaying => "removePlaying",
        }
    }

    fn get_invocation(&self) -> String {
        return format!(
            "{}({});",
            self.get_invocation_name(),
            serde_json::to_string(&self).unwrap()
        );
    }
}

fn main() {
    let event_loop = EventLoopBuilder::<JukeboxEvent>::with_user_event().build();
    let proxy = event_loop.create_proxy();

    let window = WindowBuilder::new()
        .with_fullscreen(Some(Fullscreen::Borderless(None)))
        .build(&event_loop)
        .unwrap();
    let vbox = window.default_vbox().unwrap();

    let webview = WebViewBuilder::new()
        .with_html(webapp())
        .with_focused(true)
        .build_gtk(vbox)
        .unwrap();

    thread::spawn(move || {
        thread::sleep(Duration::from_secs(2));
        loop {
            proxy
                .send_event(JukeboxEvent::ShowPlaying {
                    cover: build_data_url("image/jpeg", ALBUM_COVER_1),
                    title: String::from("The Great Gig in the Sky"),
                    artist: String::from("Pink Floyd"),
                    album: String::from("The Dark Side of the Moon"),
                })
                .unwrap();
            thread::sleep(Duration::from_secs(3));
            proxy.send_event(JukeboxEvent::RemovePlaying).unwrap();
            thread::sleep(Duration::from_secs(3));
            proxy
                .send_event(JukeboxEvent::ShowPlaying {
                    cover: build_data_url("image/jpeg", ALBUM_COVER_2),
                    title: String::from("Boulevard of Broken Dreams"),
                    artist: String::from("Green Day"),
                    album: String::from("American Idiot"),
                })
                .unwrap();
            thread::sleep(Duration::from_secs(3));
        }
    });

    event_loop.run(move |event, _, control_flow| {
        *control_flow = ControlFlow::Wait;
        match event {
            Event::UserEvent(jukebox_event) => {
                let js = jukebox_event.get_invocation();
                webview.evaluate_script(&js).unwrap();
            }
            _ => {}
        }
    });
}

fn build_data_url(mimetype: &str, input: impl AsRef<[u8]>) -> String {
    format!(
        "data:{};base64,{}",
        mimetype,
        BASE64_STANDARD.encode(&input)
    )
}

fn webapp() -> Markup {
    let b64 = build_data_url("font/ttf;charset=utf-8", RALEWAY);
    let b64_italic = build_data_url("font/ttf;charset=utf-8", RALEWAY_ITALIC);
    let fontface_defs = format!(
        r#"
        @font-face {{
            font-family: 'Raleway';
            src: url('{b64}') format('truetype');
            font-style: normal;
        }}
        @font-face {{
            font-family: 'Raleway';
            src: url('{b64_italic}') format('truetype');
            font-style: italic;
        }}
    "#
    );
    html! {
        style { (PreEscaped(fontface_defs)) }
        style { (PreEscaped(STYLESHEET)) }
        script { (PreEscaped(SCRIPT)) }
    }
}
