use actix_web::HttpResponse;
use maud::{Markup, Render, html};

use super::Page;
use super::components::{Complaint, PasswordField, TextField};

/// What the registration form shows when it is (re)rendered: the values to
/// put back in the fields, and any complaint about the last attempt.
pub struct RegisterForm {
    pub name: Option<String>,
    pub email: Option<String>,
    pub invite: Option<String>,
    pub error: Option<String>,
}

pub(super) struct RegisterBody<'a> {
    form: &'a RegisterForm,
}

impl Render for RegisterBody<'_> {
    fn render(&self) -> Markup {
        html! {
            h2 { "Register" }
            (Complaint(self.form.error.as_deref()))
            form method="post" action="/register" {
                @if let Some(invite) = &self.form.invite {
                    input type="hidden" name="invite" value=(invite) {}
                }
                (TextField {
                    label: Some("Name"),
                    name: "name",
                    input_type: "text",
                    value: self.form.name.as_deref(),
                    required: true,
                    maxlength: u32::MAX,
                })
                (TextField {
                    label: Some("Email"),
                    name: "email",
                    input_type: "email",
                    value: self.form.email.as_deref(),
                    required: true,
                    maxlength: u32::MAX,
                })
                (PasswordField {
                    label: "Password",
                    name: "password",
                    required: true,
                })
                button type="submit" { "Register" }
            }
        }
    }
}

/// A complaint shown in place of the registration form.
pub(super) struct RegisterClosedBody<'a> {
    message: &'a str,
}

impl Render for RegisterClosedBody<'_> {
    fn render(&self) -> Markup {
        html! {
            h2 { "Register" }
            (Complaint(Some(self.message)))
        }
    }
}

/// What the login form shows when it is (re)rendered.
pub struct LoginForm {
    pub name: Option<String>,
    pub error: Option<String>,
}

pub(super) struct LoginBody<'a> {
    form: &'a LoginForm,
}

impl Render for LoginBody<'_> {
    fn render(&self) -> Markup {
        html! {
            h2 { "Log in" }
            (Complaint(self.form.error.as_deref()))
            form method="post" action="/login" {
                (TextField {
                    label: Some("Name"),
                    name: "name",
                    input_type: "text",
                    value: self.form.name.as_deref(),
                    required: true,
                    maxlength: u32::MAX,
                })
                (PasswordField {
                    label: "Password",
                    name: "password",
                    required: true,
                })
                button type="submit" { "Log in" }
            }
        }
    }
}

/// The registration page, showing `form`'s values and complaint.
pub fn register(viewer: Option<&str>, form: &RegisterForm) -> HttpResponse {
    Page {
        title: "Frogue - Register".to_string(),
        viewer: viewer.map(str::to_string),
        extra_head: None,
        body: RegisterBody { form },
    }
    .into_response()
}

/// The login page, showing `form`'s values and complaint.
pub fn login(viewer: Option<&str>, form: &LoginForm) -> HttpResponse {
    Page {
        title: "Frogue - Log in".to_string(),
        viewer: viewer.map(str::to_string),
        extra_head: None,
        body: LoginBody { form },
    }
    .into_response()
}

/// The registration page, showing `message` instead of the form (for closed
/// mode).
pub fn register_closed(viewer: Option<&str>, message: &str) -> HttpResponse {
    Page {
        title: "Frogue - Register".to_string(),
        viewer: viewer.map(str::to_string),
        extra_head: None,
        body: RegisterClosedBody { message },
    }
    .into_response()
}
