use utoipa::openapi::{self, tag::TagBuilder, InfoBuilder};
use utoipa::OpenApi;

pub struct ApiDoc;

impl OpenApi for ApiDoc {
    fn openapi() -> openapi::OpenApi {
        let mut doc = crate::routes::health::HealthApiDoc::openapi();
        doc.merge(crate::routes::auth::AuthApiDoc::openapi());
        doc.merge(crate::routes::documents::DocumentsApiDoc::openapi());
        doc.merge(crate::routes::folders::FoldersApiDoc::openapi());
        doc.merge(crate::routes::tags::TagsApiDoc::openapi());
        doc.merge(crate::routes::correspondents::CorrespondentsApiDoc::openapi());
        doc.merge(crate::routes::profile::ProfileApiDoc::openapi());

        doc.info = InfoBuilder::new()
            .title("Papercrate API")
            .version(env!("CARGO_PKG_VERSION"))
            .build();

        doc.tags = Some(vec![
            TagBuilder::new()
                .name("Health")
                .description(Some("Service health"))
                .build(),
            TagBuilder::new()
                .name("Auth")
                .description(Some("Authentication"))
                .build(),
            TagBuilder::new()
                .name("Documents")
                .description(Some("Document management"))
                .build(),
            TagBuilder::new()
                .name("Assets")
                .description(Some("Document assets"))
                .build(),
            TagBuilder::new()
                .name("Folders")
                .description(Some("Folder management"))
                .build(),
            TagBuilder::new()
                .name("Tags")
                .description(Some("Tag catalog"))
                .build(),
            TagBuilder::new()
                .name("Correspondents")
                .description(Some("Correspondent catalog"))
                .build(),
            TagBuilder::new()
                .name("Profile")
                .description(Some("User profile and WebDAV tokens"))
                .build(),
        ]);

        doc
    }
}

pub mod schemas {
    pub use crate::auth::passkeys::{
        AuthenticationChallengeResponse, PasskeyLoginFinishPayload, PasskeyLoginStartPayload,
        PasskeyRegistrationFinishPayload, PasskeySummary, RegistrationChallengeResponse,
    };
    pub use crate::auth::AuthenticatedUser;
    pub use crate::documents::asset::{
        DocumentAssetDetailResponse, DocumentAssetObjectResponse, DocumentAssetResponse,
        DocumentVersionDetailResponse, DocumentVersionResponse,
    };
    pub use crate::documents::correspondents::DocumentCorrespondentResponse;
    pub use crate::models::ApiTokenCapability;
    pub use crate::routes::auth::{
        ApiTokenExchangeRequest, LoginRequest, LoginResponse, LoginResponseVariants,
        SignupFinishRequest, SignupStartRequest, SignupStartResponse, TenantListResponse,
        TenantSelectionRequest, TenantSelectionResponse, TenantSnippet,
    };
    pub use crate::routes::correspondents::{
        CorrespondentSummary, CorrespondentUsage, CreateCorrespondentRequest,
        UpdateCorrespondentRequest,
    };
    pub use crate::routes::documents::{
        AssetObjectsQuery, AssetRequestQuery, AssignCorrespondentsRequest, AssignTagsRequest,
        BulkCorrespondentAction, BulkCorrespondentResponse, BulkCorrespondentsRequest,
        BulkMoveRequest, BulkMoveResponse, BulkReanalyzeResponse, BulkReanalyzeSelectionRequest,
        BulkTagAction, BulkTagRequest, BulkTagResponse, CorrespondentAssignmentInput,
        DocumentCheckQuery, DocumentCheckResponse, DocumentDetailResponse, DocumentListQuery,
        DocumentMetadataUpdate, DocumentResponse, DocumentStatusFilter, MoveDocumentRequest,
        RestoreDocumentRequest, TagResponse, UpdateDocumentRequest, UploadDocumentForm,
    };
    pub use crate::routes::folders::{
        CreateFolderRequest, EnsureFolderPathRequest, FolderContentsQuery, FolderContentsResponse,
        FolderInfo, FolderResponse, UpdateFolderRequest,
    };
    pub use crate::routes::profile::{
        ApiTokenCreatedResponse, ApiTokenResponse, CreateApiTokenRequest, RevokePasskeyQuery,
        UpdateApiTokenCapabilitiesRequest,
    };
    pub use crate::routes::tags::{CreateTagRequest, TagCatalogEntry, UpdateTagRequest};
}

#[cfg(test)]
mod tests {
    use super::ApiDoc;
    use utoipa::OpenApi;

    #[test]
    fn openapi_serializes() {
        let spec = ApiDoc::openapi();
        let _ = serde_json::to_string(&spec).expect("serialize openapi");
    }
}
