use async_trait::async_trait;
use chrono::{DateTime, Utc};

use crate::entity::{
    AuthAccount, AuthApiKey, AuthInvitation, AuthMember, AuthOrganization, AuthPasskey,
    AuthSession, AuthTwoFactor, AuthUser, AuthVerification,
};
use crate::error::AuthResult;
use crate::types::{
    AdminAuditLog, AthenaClient, CreateAccount, CreateAdminAuditLog, CreateApiKey,
    CreateAthenaClient, CreateEmailSendFailure, CreateEmailTemplate, CreateInvitation,
    CreateMember, CreateOAuthClient, CreateOrganization, CreatePasskey, CreateSentEmail,
    CreateSession, CreateSessionIpProfileRecord, CreateTwoFactor, CreateUser, CreateVerification,
    EmailEventType, EmailSendFailure, EmailTemplate, InvitationStatus, IpProfileRecord,
    ListAdminAuditLogsParams, ListEmailEventTypesParams, ListEmailSendFailuresParams,
    ListEmailTemplatesParams, ListSentEmailsParams, ListUsersParams, OAuthClient, SentEmail,
    SessionIpProfileRecord, UpdateAccount, UpdateApiKey, UpdateEmailSendFailure,
    UpdateEmailTemplate, UpdateOrganization, UpdateSentEmail, UpdateUser, UpsertIpProfileRecord,
};

/// User persistence operations.
#[async_trait]
pub trait UserOps: Send + Sync + 'static {
    type User: AuthUser;

    async fn create_user(&self, user: CreateUser) -> AuthResult<Self::User>;
    async fn get_user_by_id(&self, id: &str) -> AuthResult<Option<Self::User>>;
    async fn get_user_by_email(&self, email: &str) -> AuthResult<Option<Self::User>>;
    async fn get_user_by_username(&self, username: &str) -> AuthResult<Option<Self::User>>;
    async fn update_user(&self, id: &str, update: UpdateUser) -> AuthResult<Self::User>;
    async fn delete_user(&self, id: &str) -> AuthResult<()>;
    /// List users with optional filtering, sorting, and pagination.
    /// Returns `(users, total_count)`.
    async fn list_users(&self, params: ListUsersParams) -> AuthResult<(Vec<Self::User>, usize)>;
}

/// Session persistence operations.
#[async_trait]
pub trait SessionOps: Send + Sync + 'static {
    type Session: AuthSession;

    async fn create_session(&self, session: CreateSession) -> AuthResult<Self::Session>;
    async fn get_session(&self, token: &str) -> AuthResult<Option<Self::Session>>;
    async fn get_user_sessions(&self, user_id: &str) -> AuthResult<Vec<Self::Session>>;
    async fn update_session_expiry(&self, token: &str, expires_at: DateTime<Utc>)
    -> AuthResult<()>;
    async fn delete_session(&self, token: &str) -> AuthResult<()>;
    async fn delete_user_sessions(&self, user_id: &str) -> AuthResult<()>;
    async fn delete_expired_sessions(&self) -> AuthResult<usize>;
    async fn update_session_active_organization(
        &self,
        token: &str,
        organization_id: Option<&str>,
    ) -> AuthResult<Self::Session>;

    /// Look up an IP profile by IP address.
    async fn get_ip_profile_by_ip(&self, ip_address: &str) -> AuthResult<Option<IpProfileRecord>> {
        let _ = ip_address;
        Ok(None)
    }

    /// Upsert an IP profile row and return the persisted record.
    async fn upsert_ip_profile(
        &self,
        input: UpsertIpProfileRecord,
    ) -> AuthResult<Option<IpProfileRecord>> {
        let _ = input;
        Ok(None)
    }

    /// Create (or update) the per-session IP profile projection.
    async fn create_session_ip_profile(
        &self,
        input: CreateSessionIpProfileRecord,
    ) -> AuthResult<Option<SessionIpProfileRecord>> {
        let _ = input;
        Ok(None)
    }

    /// Return the latest known country code for a user from session profile
    /// rows. `exclude_session_id` can be used to ignore a just-created session.
    async fn get_latest_session_country_code(
        &self,
        user_id: &str,
        exclude_session_id: Option<&str>,
    ) -> AuthResult<Option<String>> {
        let _ = (user_id, exclude_session_id);
        Ok(None)
    }

    /// Return the session profile row for the given session id, if any.
    async fn get_session_ip_profile_by_session_id(
        &self,
        session_id: &str,
    ) -> AuthResult<Option<SessionIpProfileRecord>> {
        let _ = session_id;
        Ok(None)
    }
}

/// Account (OAuth provider linking) persistence operations.
#[async_trait]
pub trait AccountOps: Send + Sync + 'static {
    type Account: AuthAccount;

    async fn create_account(&self, account: CreateAccount) -> AuthResult<Self::Account>;
    async fn get_account(
        &self,
        provider: &str,
        provider_account_id: &str,
    ) -> AuthResult<Option<Self::Account>>;
    async fn get_user_accounts(&self, user_id: &str) -> AuthResult<Vec<Self::Account>>;
    async fn update_account(&self, id: &str, update: UpdateAccount) -> AuthResult<Self::Account>;
    async fn delete_account(&self, id: &str) -> AuthResult<()>;
}

/// Verification token persistence operations.
#[async_trait]
pub trait VerificationOps: Send + Sync + 'static {
    type Verification: AuthVerification;

    async fn create_verification(
        &self,
        verification: CreateVerification,
    ) -> AuthResult<Self::Verification>;
    async fn get_verification(
        &self,
        identifier: &str,
        value: &str,
    ) -> AuthResult<Option<Self::Verification>>;
    async fn get_verification_by_value(
        &self,
        value: &str,
    ) -> AuthResult<Option<Self::Verification>>;
    async fn get_verification_by_identifier(
        &self,
        identifier: &str,
    ) -> AuthResult<Option<Self::Verification>> {
        let _ = identifier;
        Ok(None)
    }
    /// Atomically consume a verification token identified by `(identifier, value)`.
    ///
    /// Implementations should remove the token if it exists and is valid, then
    /// return the removed record. This prevents replay and race windows from
    /// split read-then-delete flows.
    async fn consume_verification(
        &self,
        identifier: &str,
        value: &str,
    ) -> AuthResult<Option<Self::Verification>>;
    /// Persist an email delivery failure record.
    ///
    /// Default implementation is a no-op so non-SQL adapters do not need to
    /// provide storage for this diagnostic signal.
    async fn create_email_send_failure(&self, failure: CreateEmailSendFailure) -> AuthResult<()> {
        let _ = failure;
        Ok(())
    }
    /// Persist an email delivery failure record and return the created row.
    ///
    /// Adapters that support durable email failure storage should override this
    /// to return the inserted entity including its generated ID/timestamps.
    async fn create_email_send_failure_record(
        &self,
        failure: CreateEmailSendFailure,
    ) -> AuthResult<EmailSendFailure> {
        let _ = failure;
        Err(crate::error::AuthError::config(
            "create_email_send_failure_record is not implemented",
        ))
    }
    /// Persist a successfully delivered email (audit log).
    ///
    /// Default implementation is a no-op for adapters without this table.
    async fn create_sent_email(&self, sent: CreateSentEmail) -> AuthResult<()> {
        let _ = sent;
        Ok(())
    }
    /// Persist a successfully delivered email and return the created row.
    ///
    /// Adapters that support durable sent-email storage should override this to
    /// return the inserted entity including its generated ID/timestamps.
    async fn create_sent_email_record(&self, sent: CreateSentEmail) -> AuthResult<SentEmail> {
        let _ = sent;
        Err(crate::error::AuthError::config(
            "create_sent_email_record is not implemented",
        ))
    }
    /// List sent emails globally, newest first.
    async fn list_sent_emails(&self, limit: usize, offset: usize) -> AuthResult<Vec<SentEmail>> {
        self.list_sent_emails_with_params(ListSentEmailsParams {
            limit: Some(limit),
            offset: Some(offset),
            ..Default::default()
        })
        .await
    }
    /// List sent emails with optional filters and pagination.
    async fn list_sent_emails_with_params(
        &self,
        params: ListSentEmailsParams,
    ) -> AuthResult<Vec<SentEmail>> {
        let _ = params;
        Ok(Vec::new())
    }
    /// Count sent emails matching optional filters.
    ///
    /// This count should ignore `limit` and `offset` fields on `params`.
    async fn count_sent_emails(&self, params: ListSentEmailsParams) -> AuthResult<usize> {
        let _ = params;
        Err(crate::error::AuthError::config(
            "count_sent_emails is not implemented",
        ))
    }
    /// List sent emails for a specific recipient email, newest first.
    async fn list_sent_emails_for_recipient(
        &self,
        recipient_email: &str,
        limit: usize,
        offset: usize,
    ) -> AuthResult<Vec<SentEmail>> {
        self.list_sent_emails_with_params(ListSentEmailsParams {
            limit: Some(limit),
            offset: Some(offset),
            recipient_email: Some(recipient_email.to_string()),
            ..Default::default()
        })
        .await
    }
    /// Fetch a sent email by ID.
    async fn get_sent_email_by_id(&self, id: &str) -> AuthResult<Option<SentEmail>> {
        let _ = id;
        Ok(None)
    }
    /// Update a sent email by ID.
    async fn update_sent_email(&self, id: &str, update: UpdateSentEmail) -> AuthResult<SentEmail> {
        let _ = (id, update);
        Err(crate::error::AuthError::not_found("Sent email not found"))
    }
    /// Delete a sent email by ID.
    async fn delete_sent_email(&self, id: &str) -> AuthResult<()> {
        let _ = id;
        Ok(())
    }
    /// List email send failures with optional filters and pagination.
    async fn list_email_send_failures(
        &self,
        params: ListEmailSendFailuresParams,
    ) -> AuthResult<Vec<EmailSendFailure>> {
        let _ = params;
        Ok(Vec::new())
    }
    /// Count email send failures matching optional filters.
    ///
    /// This count should ignore `limit` and `offset` fields on `params`.
    async fn count_email_send_failures(
        &self,
        params: ListEmailSendFailuresParams,
    ) -> AuthResult<usize> {
        let _ = params;
        Err(crate::error::AuthError::config(
            "count_email_send_failures is not implemented",
        ))
    }
    /// Fetch an email send failure by ID.
    async fn get_email_send_failure_by_id(&self, id: &str) -> AuthResult<Option<EmailSendFailure>> {
        let _ = id;
        Ok(None)
    }
    /// Update an email send failure by ID.
    async fn update_email_send_failure(
        &self,
        id: &str,
        update: UpdateEmailSendFailure,
    ) -> AuthResult<EmailSendFailure> {
        let _ = (id, update);
        Err(crate::error::AuthError::not_found(
            "Email send failure not found",
        ))
    }
    /// Delete an email send failure by ID.
    async fn delete_email_send_failure(&self, id: &str) -> AuthResult<()> {
        let _ = id;
        Ok(())
    }
    /// Fetch the active email template for `template_key`, optionally using locale preference.
    ///
    /// Adapters can return `None` to indicate no override exists (the caller
    /// will fall back to built-in defaults).
    async fn get_active_email_template(
        &self,
        template_key: &str,
        locale: Option<&str>,
    ) -> AuthResult<Option<EmailTemplate>> {
        let _ = (template_key, locale);
        Ok(None)
    }
    /// Fetch the active email template for a canonical event type and fallback template key.
    ///
    /// Default implementation falls back to [`DatabaseAdapter::get_active_email_template`]
    /// to preserve compatibility for adapters that only support `template_key` lookups.
    async fn get_active_email_template_for_event(
        &self,
        event_type: &str,
        template_key: &str,
        locale: Option<&str>,
    ) -> AuthResult<Option<EmailTemplate>> {
        let _ = event_type;
        self.get_active_email_template(template_key, locale).await
    }
    /// Create a new email template row.
    async fn create_email_template(&self, input: CreateEmailTemplate) -> AuthResult<EmailTemplate> {
        let _ = input;
        Err(crate::error::AuthError::config(
            "email template persistence is not configured",
        ))
    }
    /// List email templates with optional filters.
    async fn list_email_templates(
        &self,
        params: ListEmailTemplatesParams,
    ) -> AuthResult<Vec<EmailTemplate>> {
        let _ = params;
        Ok(Vec::new())
    }
    /// Fetch an email template by ID.
    async fn get_email_template_by_id(&self, id: &str) -> AuthResult<Option<EmailTemplate>> {
        let _ = id;
        Ok(None)
    }
    /// Count email templates matching optional filters.
    ///
    /// This count should ignore `limit` and `offset` fields on `params`.
    async fn count_email_templates(&self, params: ListEmailTemplatesParams) -> AuthResult<usize> {
        let _ = params;
        Err(crate::error::AuthError::config(
            "count_email_templates is not implemented",
        ))
    }
    /// Update an email template by ID.
    async fn update_email_template(
        &self,
        id: &str,
        update: UpdateEmailTemplate,
    ) -> AuthResult<EmailTemplate> {
        let _ = (id, update);
        Err(crate::error::AuthError::not_found(
            "Email template not found",
        ))
    }
    /// Delete an email template by ID.
    async fn delete_email_template(&self, id: &str) -> AuthResult<()> {
        let _ = id;
        Ok(())
    }
    /// List canonical email event types with optional filters.
    async fn list_email_event_types(
        &self,
        params: ListEmailEventTypesParams,
    ) -> AuthResult<Vec<EmailEventType>> {
        let _ = params;
        Ok(Vec::new())
    }
    /// Count email event types matching optional filters.
    ///
    /// This count should ignore `limit` and `offset` fields on `params`.
    async fn count_email_event_types(
        &self,
        params: ListEmailEventTypesParams,
    ) -> AuthResult<usize> {
        let _ = params;
        Err(crate::error::AuthError::config(
            "count_email_event_types is not implemented",
        ))
    }
    /// Fetch an email event type by identifier.
    async fn get_email_event_type(&self, event_type: &str) -> AuthResult<Option<EmailEventType>> {
        let _ = event_type;
        Ok(None)
    }
    /// Persist an admin audit event.
    async fn create_admin_audit_log(&self, log: CreateAdminAuditLog) -> AuthResult<()> {
        let _ = log;
        Ok(())
    }
    /// Fetch admin audit events in descending creation order.
    async fn list_admin_audit_logs(
        &self,
        limit: usize,
        offset: usize,
    ) -> AuthResult<Vec<AdminAuditLog>> {
        self.list_admin_audit_logs_with_params(ListAdminAuditLogsParams {
            limit: Some(limit),
            offset: Some(offset),
            ..Default::default()
        })
        .await
    }
    /// List admin audit events with optional filters and pagination.
    async fn list_admin_audit_logs_with_params(
        &self,
        params: ListAdminAuditLogsParams,
    ) -> AuthResult<Vec<AdminAuditLog>> {
        let _ = params;
        Ok(Vec::new())
    }
    /// Count admin audit events matching optional filters.
    ///
    /// This count should ignore `limit` and `offset` fields on `params`.
    async fn count_admin_audit_logs(&self, params: ListAdminAuditLogsParams) -> AuthResult<usize> {
        let _ = params;
        Err(crate::error::AuthError::config(
            "count_admin_audit_logs is not implemented",
        ))
    }
    /// Create an Athena client registry record.
    async fn create_athena_client(&self, input: CreateAthenaClient) -> AuthResult<AthenaClient> {
        let now = Utc::now();
        Ok(AthenaClient {
            id: String::new(),
            client_name: input.client_name,
            description: input.description,
            is_active: input.is_active.unwrap_or(true),
            pg_uri_env_var: input.pg_uri_env_var,
            metadata: input.metadata.unwrap_or_else(|| serde_json::json!({})),
            created_at: now,
            updated_at: now,
        })
    }
    /// List Athena clients.
    async fn list_athena_clients(&self) -> AuthResult<Vec<AthenaClient>> {
        Ok(Vec::new())
    }
    /// Create an OAuth client registry record.
    async fn create_oauth_client(&self, input: CreateOAuthClient) -> AuthResult<OAuthClient>;
    /// List OAuth clients.
    async fn list_oauth_clients(&self) -> AuthResult<Vec<OAuthClient>>;
    /// Find an active OAuth client by provider and allowed redirect URI.
    async fn find_active_oauth_client_by_provider_and_redirect_uri(
        &self,
        provider: &str,
        redirect_uri: &str,
    ) -> AuthResult<Option<OAuthClient>>;
    async fn delete_verification(&self, id: &str) -> AuthResult<()>;
    async fn delete_expired_verifications(&self) -> AuthResult<usize>;
}

/// Organization persistence operations.
#[async_trait]
pub trait OrganizationOps: Send + Sync + 'static {
    type Organization: AuthOrganization;

    async fn create_organization(&self, org: CreateOrganization) -> AuthResult<Self::Organization>;
    async fn get_organization_by_id(&self, id: &str) -> AuthResult<Option<Self::Organization>>;
    async fn get_organization_by_slug(&self, slug: &str) -> AuthResult<Option<Self::Organization>>;
    async fn update_organization(
        &self,
        id: &str,
        update: UpdateOrganization,
    ) -> AuthResult<Self::Organization>;
    async fn delete_organization(&self, id: &str) -> AuthResult<()>;
    async fn list_user_organizations(&self, user_id: &str) -> AuthResult<Vec<Self::Organization>>;
}

/// Organization member persistence operations.
#[async_trait]
pub trait MemberOps: Send + Sync + 'static {
    type Member: AuthMember;

    async fn create_member(&self, member: CreateMember) -> AuthResult<Self::Member>;
    async fn get_member(
        &self,
        organization_id: &str,
        user_id: &str,
    ) -> AuthResult<Option<Self::Member>>;
    async fn get_member_by_id(&self, id: &str) -> AuthResult<Option<Self::Member>>;
    async fn update_member_role(&self, member_id: &str, role: &str) -> AuthResult<Self::Member>;
    async fn delete_member(&self, member_id: &str) -> AuthResult<()>;
    async fn list_organization_members(
        &self,
        organization_id: &str,
    ) -> AuthResult<Vec<Self::Member>>;
    async fn count_organization_members(&self, organization_id: &str) -> AuthResult<usize>;
    async fn count_organization_owners(&self, organization_id: &str) -> AuthResult<usize>;
}

/// Invitation persistence operations.
#[async_trait]
pub trait InvitationOps: Send + Sync + 'static {
    type Invitation: AuthInvitation;

    async fn create_invitation(&self, invitation: CreateInvitation)
    -> AuthResult<Self::Invitation>;
    async fn get_invitation_by_id(&self, id: &str) -> AuthResult<Option<Self::Invitation>>;
    async fn get_pending_invitation(
        &self,
        organization_id: &str,
        email: &str,
    ) -> AuthResult<Option<Self::Invitation>>;
    async fn update_invitation_status(
        &self,
        id: &str,
        status: InvitationStatus,
    ) -> AuthResult<Self::Invitation>;
    async fn list_organization_invitations(
        &self,
        organization_id: &str,
    ) -> AuthResult<Vec<Self::Invitation>>;
    async fn list_user_invitations(&self, email: &str) -> AuthResult<Vec<Self::Invitation>>;
}

/// Two-factor authentication persistence operations.
#[async_trait]
pub trait TwoFactorOps: Send + Sync + 'static {
    type TwoFactor: AuthTwoFactor;

    async fn create_two_factor(&self, two_factor: CreateTwoFactor) -> AuthResult<Self::TwoFactor>;
    async fn get_two_factor_by_user_id(&self, user_id: &str)
    -> AuthResult<Option<Self::TwoFactor>>;
    async fn update_two_factor_backup_codes(
        &self,
        user_id: &str,
        backup_codes: &str,
    ) -> AuthResult<Self::TwoFactor>;
    async fn delete_two_factor(&self, user_id: &str) -> AuthResult<()>;
}

/// API key persistence operations.
#[async_trait]
pub trait ApiKeyOps: Send + Sync + 'static {
    type ApiKey: AuthApiKey;

    async fn create_api_key(&self, input: CreateApiKey) -> AuthResult<Self::ApiKey>;
    async fn get_api_key_by_id(&self, id: &str) -> AuthResult<Option<Self::ApiKey>>;
    async fn get_api_key_by_hash(&self, hash: &str) -> AuthResult<Option<Self::ApiKey>>;
    async fn list_api_keys_by_user(&self, user_id: &str) -> AuthResult<Vec<Self::ApiKey>>;
    async fn update_api_key(&self, id: &str, update: UpdateApiKey) -> AuthResult<Self::ApiKey>;
    async fn delete_api_key(&self, id: &str) -> AuthResult<()>;
    /// Delete all API keys whose `expires_at` is in the past. Returns the count of deleted keys.
    async fn delete_expired_api_keys(&self) -> AuthResult<usize>;
}

/// Passkey persistence operations.
#[async_trait]
pub trait PasskeyOps: Send + Sync + 'static {
    type Passkey: AuthPasskey;

    async fn create_passkey(&self, input: CreatePasskey) -> AuthResult<Self::Passkey>;
    async fn get_passkey_by_id(&self, id: &str) -> AuthResult<Option<Self::Passkey>>;
    async fn get_passkey_by_credential_id(
        &self,
        credential_id: &str,
    ) -> AuthResult<Option<Self::Passkey>>;
    async fn list_passkeys_by_user(&self, user_id: &str) -> AuthResult<Vec<Self::Passkey>>;
    async fn update_passkey_counter(&self, id: &str, counter: u64) -> AuthResult<Self::Passkey>;
    async fn update_passkey_name(&self, id: &str, name: &str) -> AuthResult<Self::Passkey>;
    async fn delete_passkey(&self, id: &str) -> AuthResult<()>;
}
