use askama::Template;
use askama_web::WebTemplate;
use axum::extract::State;
use axum::http::HeaderMap;
use axum::response::{IntoResponse, Response};
use axum::Form;
use serde::Deserialize;

use crate::page::PageContext;
use crate::state::AppState;

#[derive(Deserialize)]
pub struct ReportQuery {
    pub url: Option<String>,
}

#[derive(Template, WebTemplate)]
#[template(path = "report.html")]
pub struct ReportTemplate {
    pub page: PageContext,
    pub is_admin: bool,
    pub prefill_url: String,
}

#[derive(Template, WebTemplate)]
#[template(path = "report_submitted.html")]
pub struct ReportSubmittedTemplate {
    pub page: PageContext,
    pub is_admin: bool,
    pub report_id: i64,
}

pub async fn form(
    headers: HeaderMap,
    State(state): State<AppState>,
    axum::extract::Query(q): axum::extract::Query<ReportQuery>,
) -> ReportTemplate {
    let page = PageContext::from_request(&headers, &state.announcement);
    ReportTemplate {
        page,
        is_admin: false,
        prefill_url: q.url.unwrap_or_default(),
    }
}

#[derive(Deserialize)]
pub struct ReportForm {
    content_url: String,
    reason: String,
    description: Option<String>,
    reporter_email: Option<String>,
}

fn parse_content_ref(url: &str) -> Option<(&'static str, String)> {
    if let Some(id) = url
        .trim_end_matches('/')
        .strip_prefix("https://irc.pics/")
        .or_else(|| url.trim_end_matches('/').strip_prefix("http://irc.pics/"))
    {
        let id = id.split('/').next().unwrap_or(id);
        if !id.is_empty() && !id.starts_with("auth") && !id.starts_with("api") {
            return Some(("image", id.to_string()));
        }
    }
    if let Some(id) = url
        .trim_end_matches('/')
        .strip_prefix("https://txt.irc.now/")
        .or_else(|| url.trim_end_matches('/').strip_prefix("http://txt.irc.now/"))
    {
        let id = id.split('/').next().unwrap_or(id);
        if !id.is_empty() && !id.starts_with("auth") && !id.starts_with("api") {
            return Some(("paste", id.to_string()));
        }
    }
    None
}

pub async fn submit(
    headers: HeaderMap,
    State(state): State<AppState>,
    Form(form): Form<ReportForm>,
) -> Response {
    let page = PageContext::from_request(&headers, &state.announcement);

    if form.content_url.is_empty() || form.reason.is_empty() {
        return ReportTemplate {
            page,
            is_admin: false,
            prefill_url: form.content_url,
        }
        .into_response();
    }

    let valid_reasons = ["csam", "illegal", "harassment", "copyright", "spam", "other"];
    if !valid_reasons.contains(&form.reason.as_str()) {
        return ReportTemplate {
            page,
            is_admin: false,
            prefill_url: form.content_url,
        }
        .into_response();
    }

    let description = form
        .description
        .as_deref()
        .map(|d| &d[..d.len().min(2000)])
        .filter(|d| !d.trim().is_empty());

    let reporter_email = form
        .reporter_email
        .as_deref()
        .filter(|e| !e.trim().is_empty());

    let (content_type, content_id) = match parse_content_ref(&form.content_url) {
        Some(r) => r,
        None => {
            return ReportTemplate {
                page,
                is_admin: false,
                prefill_url: form.content_url,
            }
            .into_response();
        }
    };

    let result = sqlx::query_scalar::<_, i64>(
        "INSERT INTO abuse_reports (content_type, content_id, content_url, reporter_email, reason, description)
         VALUES ($1, $2, $3, $4, $5, $6)
         RETURNING id",
    )
    .bind(content_type)
    .bind(&content_id)
    .bind(&form.content_url)
    .bind(reporter_email)
    .bind(&form.reason)
    .bind(description)
    .fetch_one(&state.db)
    .await;

    match result {
        Ok(report_id) => {
            tracing::info!("abuse report #{report_id} submitted for {content_type}/{content_id}");
            ReportSubmittedTemplate { page, is_admin: false, report_id }.into_response()
        }
        Err(e) => {
            tracing::error!("abuse report insert failed: {e}");
            ReportTemplate {
                page,
                is_admin: false,
                prefill_url: form.content_url,
            }
            .into_response()
        }
    }
}
