use crate::api::rest::{dto, handlers};
use crate::domain::service::Service;
use crate::infra::storage::sea_orm_repo::SeaOrmSettingsRepository;
use axum::http::StatusCode;
use axum::{Extension, Router};
use std::sync::Arc;
use toolkit::api::operation_builder::LicenseFeature;
use toolkit::api::{OpenApiRegistry, OperationBuilder};

/// Type alias for the concrete service type.
pub type ConcreteService = Service<SeaOrmSettingsRepository>;

struct License;

impl AsRef<str> for License {
    fn as_ref(&self) -> &'static str {
        "gts.cf.core.lic.feat.v1~cf.core.global.base.v1"
    }
}

impl LicenseFeature for License {}

pub fn register_routes(
    mut router: Router,
    openapi: &dyn OpenApiRegistry,
    service: Arc<ConcreteService>,
) -> Router {
    router = OperationBuilder::get("/simple-user-settings/v1/settings")
        .operation_id("simple_user_settings.get_settings")
        .summary("Get user settings")
        .description("Retrieve settings for the authenticated user")
        .tag("Settings")
        .authenticated()
        .require_license_features::<License>([])
        .handler(handlers::get_settings)
        .json_response_with_schema::<dto::SimpleUserSettingsDto>(
            openapi,
            StatusCode::OK,
            "Settings retrieved",
        )
        .error_401(openapi)
        .error_403(openapi)
        .error_500(openapi)
        .register(router, openapi);

    router = OperationBuilder::post("/simple-user-settings/v1/settings")
        .operation_id("simple_user_settings.update_settings")
        .summary("Update user settings")
        .description("Full update of user settings (POST semantics)")
        .tag("Settings")
        .authenticated()
        .require_license_features::<License>([])
        .json_request::<dto::UpdateSimpleUserSettingsRequest>(openapi, "Settings update data")
        .handler(handlers::update_settings)
        .json_response_with_schema::<dto::SimpleUserSettingsDto>(
            openapi,
            StatusCode::OK,
            "Settings updated",
        )
        .error_400(openapi)
        .error_401(openapi)
        .error_403(openapi)
        .error_422(openapi)
        .error_500(openapi)
        .register(router, openapi);

    router = OperationBuilder::patch("/simple-user-settings/v1/settings")
        .operation_id("simple_user_settings.patch_settings")
        .summary("Partially update user settings")
        .description("Partial update of user settings (PATCH semantics)")
        .tag("Settings")
        .authenticated()
        .require_license_features::<License>([])
        .json_request::<dto::PatchSimpleUserSettingsRequest>(openapi, "Settings patch data")
        .handler(handlers::patch_settings)
        .json_response_with_schema::<dto::SimpleUserSettingsDto>(
            openapi,
            StatusCode::OK,
            "Settings patched",
        )
        .error_400(openapi)
        .error_401(openapi)
        .error_403(openapi)
        .error_422(openapi)
        .error_500(openapi)
        .register(router, openapi);

    router = router.layer(Extension(service));

    router
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn test_license_as_ref() {
        let license = License;
        assert_eq!(
            license.as_ref(),
            "gts.cf.core.lic.feat.v1~cf.core.global.base.v1"
        );
    }

    #[test]
    fn test_license_implements_license_feature() {
        fn assert_license_feature<T: LicenseFeature>(_: &T) {}
        let license = License;
        assert_license_feature(&license);
    }
}
