use actix_web::{web, HttpRequest, HttpResponse};

use crate::WebData;

pub async fn host_meta(data: web::Data<WebData<'_>>) -> HttpResponse {
    HttpResponse::Ok()
        .insert_header(("Content-Type", "application/xrd+xml"))
        .insert_header((
            "Date",
            chrono::Utc::now()
                .format("%a, %d %b %Y %H:%M:%S GMT")
                .to_string(),
        ))
        .body(format!(r#"<?xml version="1.0"?>
<XRD xmlns="http://docs.oasis-open.org/ns/xri/xrd-1.0">
  <Link rel="lrdd" type="application/xrd+xml" template="{}://{}/.well-known/webfinger?resource={{uri}}"/>
</XRD>
"#, data.base_proto, data.base_domain))
}

pub async fn nodeinfo21() -> HttpResponse {
    HttpResponse::Ok()
        .insert_header((
            "Content-Type",
            "application/json;profile=\"http://nodeinfo.diaspora.software/ns/schema/2.1#\"",
        ))
        .insert_header((
            "Date",
            chrono::Utc::now()
                .format("%a, %d %b %Y %H:%M:%S GMT")
                .to_string(),
        ))
        .body(
            r#"{
        "version": "2.1",
        "software": {
            "name": "freeorion-test-web",
            "version": "0.0.1"
        },
        "protocols": ["activitypub"],
        "services": {"inbound": [], "outbound": []},
        "openRegistrations": false,
        "usage": {
            "users": {},
            "localPosts": 0
        },
        "metadata": {}
    }"#,
        )
}

pub async fn nodeinfo(data: web::Data<WebData<'_>>) -> HttpResponse {
    HttpResponse::Ok()
        .insert_header(("Content-Type", "application/jrd+json"))
        .insert_header((
            "Date",
            chrono::Utc::now()
                .format("%a, %d %b %Y %H:%M:%S GMT")
                .to_string(),
        ))
        .body(format!(
            r#"{{
        "links": [{{
            "rel": "http://nodeinfo.diaspora.software/ns/schema/2.1",
            "href": "{}://{}/nodeinfo/2.1"
        }}]
    }}"#,
            data.base_proto, data.base_domain
        ))
}

#[actix_web::get("/.well-known/webfinger")]
pub async fn webfinger(req: HttpRequest, data: web::Data<WebData<'_>>) -> HttpResponse {
    let mut resource = None;
    for params in req.query_string().split('&') {
        if let Some((k, v)) = params.split_once('=') {
            if k == "resource" {
                resource = Some(v);
            }
        }
    }
    let resource = match resource {
        Some(r) => r,
        None => {
            log::warn!("Webfinger not found resource in {}", req.query_string());
            return HttpResponse::BadRequest().body("Incorrect query");
        }
    };
    // misskey send resource as percent escaped
    let resource = match pct_str::PctStr::new(resource) {
        Ok(r) => std::borrow::Cow::Owned(r.decode()),
        Err(_) => std::borrow::Cow::Borrowed(resource),
    };
    let resource_clean = resource.trim_start_matches("acct:");
    let mut parts = resource_clean.splitn(3, '@');
    let (user, domain) = match (parts.next(), parts.next(), parts.next()) {
        (Some(u), Some(d), None) => (u, d),
        _ => {
            log::error!("Webfinger incorrect resource {}", resource);
            return HttpResponse::NotFound().body("Not found");
        }
    };
    if domain != data.base_domain {
        log::error!("Webfinger incorrect resource domain {}", resource);
        return HttpResponse::NotFound().body("Not found");
    }

    log::info!("Webfinger resource user: {}", user);
    HttpResponse::NotFound().body("Not found")
}