use utoipa::Modify;
use utoipa::OpenApi;
use utoipa::openapi::security::{
    ApiKey, ApiKeyValue, SecurityRequirement, SecurityScheme,
};

#[derive(utoipa::OpenApi)]
#[openapi(
    info(
        title = "GitDataAI API",
        version = "1.0.0",
        description = "GitDataAI platform REST API"
    ),
    tags(
        (name = "auth", description = "Authentication & 2FA"),
        (name = "user", description = "Current user settings & profile"),
        (name = "users", description = "Public user info & relationships"),
        (name = "workspace", description = "Workspace management"),
        (name = "issues", description = "Issue tracking"),
        (name = "pull_request", description = "Pull request operations"),
        (name = "git", description = "Git repository operations"),
        (name = "repos", description = "Repo management & configuration"),
        (name = "ai", description = "AI model catalog"),
        (name = "agent", description = "AI Agent sessions, conversations & streaming"),
        (name = "channel", description = "Channel WebSocket & REST fallback"),
        (name = "search", description = "Global search across workspaces, repos, channels, issues")
    ),
    paths(
        crate::auth::captcha::captcha,
        crate::auth::login::login,
        crate::auth::logout::logout,
        crate::auth::me::me,
        crate::auth::register::register,
        crate::auth::reset_pass::reset_password_request,
        crate::auth::reset_pass::reset_password_verify,
        crate::auth::rsa::rsa,
        crate::auth::totp::enable_2fa,
        crate::auth::totp::verify_2fa,
        crate::auth::totp::disable_2fa,
        crate::auth::totp::status_2fa,
        crate::auth::totp::regenerate_backup_codes,
        crate::auth::email::get_email,
        crate::auth::email::email_change_request,
        crate::auth::email::email_verify,
        crate::user::config::user_config,
        crate::user::accessibility::update_accessibility,
        crate::user::appearance::update_appearance,
        crate::user::notification::update_notification,
        crate::user::privacy::update_privacy,
        crate::user::profile::update_profile,
        crate::user::profile::upload_avatar,
        crate::user::access_token::list_access_tokens,
        crate::user::access_token::create_access_token,
        crate::user::access_token::update_access_token,
        crate::user::access_token::revoke_access_token,
        crate::user::sshkey::list_ssh_keys,
        crate::user::sshkey::add_ssh_key,
        crate::user::sshkey::update_ssh_key,
        crate::user::sshkey::revoke_ssh_key,
        crate::user::chpc::contribution_heatmap,
        crate::user::chpc::invalidate_chpc_cache,
        crate::users::summary::user_summary,
        crate::users::public::user_public,
        crate::users::chpc::user_chpc,
        crate::users::relation::follow_user,
        crate::users::relation::unfollow_user,
        crate::users::relation::block_user,
        crate::users::relation::unblock_user,
        crate::users::relation::relation_status,
        crate::users::relation::followers,
        crate::users::relation::following,
        crate::users::relation::blocked_list,
        crate::users::relation::relation_counts,
        crate::users::avatar::user_avatar,
        crate::workspace::workspace::create_workspace,
        crate::workspace::workspace::my_workspaces,
        crate::workspace::workspace::get_workspace,
        crate::workspace::workspace::update_workspace,
        crate::workspace::workspace::get_avatar,
        crate::workspace::workspace::upload_avatar,
        crate::workspace::member::list_members,
        crate::workspace::member::add_member,
        crate::workspace::member::update_member,
        crate::workspace::member::remove_member,
        crate::workspace::group::list_groups,
        crate::workspace::group::create_group,
        crate::workspace::group::update_group,
        crate::workspace::group::delete_group,
        crate::workspace::group::add_group_member,
        crate::workspace::group::remove_group_member,
        crate::workspace::group::list_group_members,
        crate::workspace::join::join_strategy,
        crate::workspace::join::update_join_strategy,
        crate::workspace::join::my_join_applies,
        crate::workspace::join::apply_join,
        crate::workspace::join::cancel_join,
        crate::workspace::join::list_join_applies,
        crate::workspace::join::approve_join,
        crate::issues::issue::create_issue,
        crate::issues::issue::list_issues,
        crate::issues::issue::get_issue,
        crate::issues::issue::update_issue,
        crate::issues::issue::delete_issue,
        crate::issues::issue::close_issue,
        crate::issues::issue::reopen_issue,
        crate::issues::comment::list_comments,
        crate::issues::comment::create_comment,
        crate::issues::comment::update_comment,
        crate::issues::comment::delete_comment,
        crate::issues::assignee::assign_user,
        crate::issues::assignee::unassign_user,
        crate::issues::label::add_issue_label,
        crate::issues::label::remove_issue_label,
        crate::issues::label::list_labels,
        crate::issues::label::create_label,
        crate::issues::label::update_label,
        crate::issues::label::delete_label,
        crate::issues::milestone::set_issue_milestone,
        crate::issues::milestone::clear_issue_milestone,
        crate::issues::milestone::list_milestones,
        crate::issues::milestone::create_milestone,
        crate::issues::milestone::update_milestone,
        crate::issues::milestone::delete_milestone,
        crate::issues::binding::bind_repo,
        crate::issues::binding::unbind_repo,
        crate::issues::binding::bind_pull_request,
        crate::issues::binding::unbind_pull_request,
        crate::issues::reaction::add_reaction,
        crate::issues::reaction::remove_reaction,
        crate::issues::reaction::add_comment_reaction,
        crate::issues::reaction::remove_comment_reaction,
        crate::issues::event::list_events,
        crate::pull_request::pull_request::list_prs,
        crate::pull_request::pull_request::create_pr,
        crate::pull_request::pull_request::get_pr,
        crate::pull_request::pull_request::update_pr,
        crate::pull_request::pull_request::delete_pr,
        crate::pull_request::merge::merge_pr,
        crate::pull_request::merge::merge_analysis,
        crate::pull_request::merge::update_branch,
        crate::pull_request::assignee::assign_user,
        crate::pull_request::assignee::unassign_user,
        crate::pull_request::comment::list_comments,
        crate::pull_request::comment::create_comment,
        crate::pull_request::comment::update_comment,
        crate::pull_request::comment::delete_comment,
        crate::pull_request::label::add_label,
        crate::pull_request::label::remove_label,
        crate::pull_request::review::list_reviews,
        crate::pull_request::review::create_review,
        crate::pull_request::review::dismiss_review,
        crate::pull_request::review::create_review_comment,
        crate::pull_request::reaction::add_reaction,
        crate::pull_request::reaction::remove_reaction,
        crate::pull_request::reaction::add_comment_reaction,
        crate::pull_request::reaction::remove_comment_reaction,
        crate::git::init::create_repo,
        crate::git::init::clone_repo,
        crate::git::repo::list_repos,
        crate::git::repo::get_repo,
        crate::git::repo::update_repo,
        crate::git::repo::delete_repo,
        crate::git::repo::archive_repo,
        crate::git::repo::transfer_repo,
        crate::git::repo::get_topics,
        crate::git::repo::update_topics,
        crate::git::fork::create_fork,
        crate::git::fork::list_forks,
        crate::git::protect::list_protects,
        crate::git::protect::create_protect,
        crate::git::protect::update_protect,
        crate::git::protect::delete_protect,
        crate::git::webhook::list_webhooks,
        crate::git::webhook::create_webhook,
        crate::git::webhook::update_webhook,
        crate::git::webhook::delete_webhook,
        crate::git::webhook::list_deliveries,
        crate::git::branch::list_branches,
        crate::git::branch::fork_branch,
        crate::git::branch::branch_info,
        crate::git::branch::ahead_behind,
        crate::git::branch::branch_upstream,
        crate::git::branch::delete_branch,
        crate::git::branch::rename_branch,
        crate::git::commit::list_commits,
        crate::git::commit::commit_info,
        crate::git::commit::commit_history,
        crate::git::commit::commit_walk,
        crate::git::commit::cherry_pick,
        crate::git::blob::blob_info,
        crate::git::blob::blob_upload,
        crate::git::blame::blame_file,
        crate::git::tree::tree_entries,
        crate::git::tree::tree_entry_by_path,
        crate::git::tree::tree_entry_by_path_from_commit,
        crate::git::diff::diff,
        crate::git::tag::list_tags,
        crate::git::tag::init_tag,
        crate::git::tag::tag_info,
        crate::git::tag::delete_tag,
        crate::git::tag::update_tag,
        crate::git::archive::archive,
        crate::git::star::star_repo,
        crate::git::star::unstar_repo,
        crate::git::star::star_status,
        crate::git::watch::watch_repo,
        crate::git::watch::unwatch_repo,
        crate::git::watch::watch_status,
        crate::git::contributor::list_contributors,
        crate::git::language::get_languages,
        crate::git::readme::get_readme,
        crate::git::readme::diff_branches,
        crate::git::refs::list_refs,
        crate::git::contents::get_contents,
        crate::git::contents::create_contents,
        crate::git::contents::update_contents,
        crate::git::contents::delete_contents,
        crate::git::compare::compare,
        crate::git::release::list_releases,
        crate::git::release::get_release,
        crate::git::release::get_release_by_tag,
        crate::git::release::create_release,
        crate::git::release::update_release,
        crate::git::release::delete_release,
        crate::git::release::delete_release_by_tag,
        crate::git::commit_status::list_statuses,
        crate::git::commit_status::combined_status,
        crate::git::commit_status::create_status,
        crate::ai::model::list_models,
        crate::ai::model::get_model,
        crate::ai::model::list_versions,
        crate::ai::model::get_card,
        crate::ai::model::list_tags,
        crate::ai::model::list_discussions,
        crate::ai::model::list_likes,
        crate::ai::provider::list_providers,
        crate::ai::provider::get_provider,
        crate::agent::session::create_session,
        crate::agent::session::list_sessions,
        crate::agent::session::get_session,
        crate::agent::session::update_session,
        crate::agent::session::delete_session,
        crate::agent::conversation::list_all_conversations,
        crate::agent::conversation::create_conversation,
        crate::agent::conversation::list_conversations,
        crate::agent::conversation::get_conversation,
        crate::agent::conversation::update_conversation,
        crate::agent::conversation::delete_conversation,
        crate::agent::conversation::list_messages,
        crate::agent::conversation::send_message,
        crate::agent::conversation::stream_agent,
        crate::channel::token::generate_token,
        crate::channel::rest::ping,
        crate::channel::rest::csrf_token,
        crate::channel::rest_message::create_message,
        crate::channel::rest_message::update_message,
        crate::channel::rest_message::revoke_message,
        crate::channel::rest_message::list_messages,
        crate::channel::rest_message::messages_around,
        crate::channel::rest_message::missed_messages,
        crate::channel::rest_message::search,
        crate::channel::rest_room::subscribe,
        crate::channel::rest_room::unsubscribe,
        crate::channel::rest_room::room_get,
        crate::channel::rest_room::room_create,
        crate::channel::rest_room::room_update,
        crate::channel::rest_room::room_delete,
        crate::channel::rest_room::access_grant,
        crate::channel::rest_room::access_revoke,
        crate::channel::rest_room::category_create,
        crate::channel::rest_room::category_update,
        crate::channel::rest_room::category_delete,
        crate::channel::rest_interact::reaction_add,
        crate::channel::rest_interact::reaction_remove,
        crate::channel::rest_interact::thread_create,
        crate::channel::rest_interact::thread_resolve,
        crate::channel::rest_interact::thread_archive,
        crate::channel::rest_interact::pin_add,
        crate::channel::rest_interact::pin_remove,
        crate::channel::rest_interact::draft_save,
        crate::channel::rest_interact::draft_clear,
        crate::channel::rest_interact::typing,
        crate::channel::rest_member::read_receipt,
        crate::channel::rest_member::dnd_update,
        crate::channel::rest_member::notification_mark_read,
        crate::channel::rest_member::notification_mark_all_read,
        crate::channel::rest_member::notification_archive,
        crate::channel::rest_member::presence_update,
        crate::channel::rest_member::custom_status_update,
        crate::channel::rest_member::invite_create,
        crate::channel::rest_member::invite_accept,
        crate::channel::rest_member::invite_revoke,
        crate::channel::rest_member::ban_create,
        crate::channel::rest_member::ban_remove,
        crate::channel::rest_voice::voice_join,
        crate::channel::rest_voice::voice_leave,
        crate::channel::rest_voice::voice_mute,
        crate::channel::rest_voice::voice_deaf,
        crate::channel::rest_voice::screen_share,
        crate::channel::rest_user::user_summary,
        crate::channel::rest_room::list_rooms,
        crate::channel::rest_article::article_create,
        crate::channel::rest_article::article_list,
        crate::channel::rest_article::article_get,
        crate::channel::rest_article::article_update,
        crate::channel::rest_article::article_delete,
        crate::channel::rest_article::article_like,
        crate::channel::rest_article::article_comment_create,
        crate::channel::rest_article::article_comment_list,
        crate::channel::rest_article::article_comment_delete,
        crate::channel::rest_article::article_liked_users,
        crate::search::search,
    ),
    modifiers(&SecurityAddon)
)]
pub struct ApiDoc;

struct SecurityAddon;

impl Modify for SecurityAddon {
    fn modify(&self, openapi: &mut utoipa::openapi::OpenApi) {
        if let Some(components) = openapi.components.as_mut() {
            components.add_security_scheme(
                "session",
                SecurityScheme::ApiKey(ApiKey::Cookie(ApiKeyValue::new("id"))),
            );
        }
        openapi.security = Some(vec![SecurityRequirement::new(
            "session",
            Vec::<String>::new(),
        )]);
        openapi.info.license = None;
        let remap = |t: &str| -> String {
            if t.starts_with("crate::") {
                let parts: Vec<&str> = t.split("::").collect();
                parts.get(1).unwrap_or(&t).to_string()
            } else {
                t.to_string()
            }
        };
        fn clean_tags(
            op: &mut utoipa::openapi::path::Operation,
            remap: impl Fn(&str) -> String,
        ) {
            if let Some(tags) = op.tags.as_mut() {
                for t in tags.iter_mut() {
                    *t = remap(t);
                }
                tags.dedup();
            }
        }
        fn prefix_operation_id(op: &mut utoipa::openapi::path::Operation) {
            if let Some(tags) = &op.tags {
                if let Some(tag) = tags.first() {
                    if let Some(id) = op.operation_id.as_mut() {
                        if !id.starts_with(tag) {
                            *id = format!("{}_{}", tag, id);
                        }
                    }
                }
            }
        }
        for (_path, item) in openapi.paths.paths.iter_mut() {
            if let Some(op) = item.get.as_mut() {
                clean_tags(op, remap);
                prefix_operation_id(op);
            }
            if let Some(op) = item.put.as_mut() {
                clean_tags(op, remap);
                prefix_operation_id(op);
            }
            if let Some(op) = item.post.as_mut() {
                clean_tags(op, remap);
                prefix_operation_id(op);
            }
            if let Some(op) = item.delete.as_mut() {
                clean_tags(op, remap);
                prefix_operation_id(op);
            }
            if let Some(op) = item.patch.as_mut() {
                clean_tags(op, remap);
                prefix_operation_id(op);
            }
            if let Some(op) = item.head.as_mut() {
                clean_tags(op, remap);
                prefix_operation_id(op);
            }
            if let Some(op) = item.options.as_mut() {
                clean_tags(op, remap);
                prefix_operation_id(op);
            }
            if let Some(op) = item.trace.as_mut() {
                clean_tags(op, remap);
                prefix_operation_id(op);
            }
        }
    }
}

pub fn openapi_json() -> String {
    ApiDoc::openapi().to_pretty_json().unwrap()
}
