use async_trait::async_trait;

use crate::{
    errors::DomainError,
    models::{
        AnnotatedRow, DiaryEntry, DiaryFilter, EntityType, ExportFormat, ExternalPersonId,
        FeedEntry, FeedSortBy, FieldMapping, FileFormat, FollowingFilter, ImportError,
        ImportProfile, ImportSession, IndexableDocument, MovieProfile, MovieStats, ParsedFile,
        Person, PersonCredits, PersonEnrichmentData, PersonId, RefreshSession, RemoteActorInfo,
        ReviewHistory, SearchQuery, SearchResults, UserStats, UserTrends, WatchlistEntry,
        WatchlistWithMovie,
        collections::{PageParams, Paginated},
    },
    ports::{
        DiaryExporter, DiaryQuery, DocumentParser, ImportProfileRepository,
        ImportSessionRepository, MovieProfileRepository, PersonCommand, PersonQuery,
        PosterFetcherClient, RefreshSessionRepository, SearchCommand, SearchPort, StatsRepository,
        UserProfileFieldsRepository, WatchlistRepository,
    },
    value_objects::{ImportProfileId, ImportSessionId, MovieId, PosterUrl, UserId},
};

// ── PanicDiaryQuery ───────────────────────────────────────────────────────────

pub struct PanicDiaryQuery;

#[async_trait]
impl DiaryQuery for PanicDiaryQuery {
    async fn query_diary(&self, _: &DiaryFilter) -> Result<Paginated<DiaryEntry>, DomainError> {
        panic!("PanicDiaryQuery called")
    }
    async fn query_activity_feed(
        &self,
        _: &PageParams,
    ) -> Result<Paginated<FeedEntry>, DomainError> {
        panic!("PanicDiaryQuery called")
    }
    async fn query_activity_feed_filtered(
        &self,
        _: &PageParams,
        _: &FeedSortBy,
        _: Option<&str>,
        _: Option<&FollowingFilter>,
    ) -> Result<Paginated<FeedEntry>, DomainError> {
        panic!("PanicDiaryQuery called")
    }
    async fn get_review_history(&self, _: &MovieId) -> Result<ReviewHistory, DomainError> {
        panic!("PanicDiaryQuery called")
    }
    async fn get_user_history(&self, _: &UserId) -> Result<Vec<DiaryEntry>, DomainError> {
        panic!("PanicDiaryQuery called")
    }
    fn stream_user_history(
        &self,
        _: UserId,
    ) -> futures::stream::BoxStream<'static, Result<DiaryEntry, DomainError>> {
        panic!("PanicDiaryQuery called")
    }
    async fn get_movie_stats(&self, _: &MovieId) -> Result<MovieStats, DomainError> {
        panic!("PanicDiaryQuery called")
    }
    async fn get_movie_social_feed(
        &self,
        _: &MovieId,
        _: &PageParams,
    ) -> Result<Paginated<FeedEntry>, DomainError> {
        panic!("PanicDiaryQuery called")
    }
    async fn count_local_posts(&self) -> Result<u64, DomainError> {
        panic!("PanicDiaryQuery called")
    }
}

pub struct PanicStatsRepository;

#[async_trait]
impl StatsRepository for PanicStatsRepository {
    async fn get_user_stats(&self, _: &UserId) -> Result<UserStats, DomainError> {
        panic!("PanicStatsRepository called")
    }
    async fn get_user_trends(&self, _: &UserId) -> Result<UserTrends, DomainError> {
        panic!("PanicStatsRepository called")
    }
    async fn count_reviews_in_year(&self, _: &UserId, _: u16) -> Result<u32, DomainError> {
        panic!("PanicStatsRepository called")
    }
}

pub struct PanicImportSessionRepository;

#[async_trait]
impl ImportSessionRepository for PanicImportSessionRepository {
    async fn create(&self, _: &ImportSession) -> Result<(), DomainError> {
        panic!("PanicImportSessionRepository called")
    }
    async fn get(
        &self,
        _: &ImportSessionId,
        _: &UserId,
    ) -> Result<Option<ImportSession>, DomainError> {
        panic!("PanicImportSessionRepository called")
    }
    async fn update(&self, _: &ImportSession) -> Result<(), DomainError> {
        panic!("PanicImportSessionRepository called")
    }
    async fn delete(&self, _: &ImportSessionId) -> Result<(), DomainError> {
        panic!("PanicImportSessionRepository called")
    }
    async fn delete_expired(&self) -> Result<u64, DomainError> {
        panic!("PanicImportSessionRepository called")
    }
    async fn delete_expired_for_user(&self, _: &UserId) -> Result<(), DomainError> {
        panic!("PanicImportSessionRepository called")
    }
}

pub struct PanicRefreshSessionRepository;

#[async_trait]
impl RefreshSessionRepository for PanicRefreshSessionRepository {
    async fn create(&self, _: &RefreshSession) -> Result<(), DomainError> {
        panic!("PanicRefreshSessionRepository called")
    }
    async fn get_by_token(&self, _: &str) -> Result<Option<RefreshSession>, DomainError> {
        panic!("PanicRefreshSessionRepository called")
    }
    async fn revoke(&self, _: &str) -> Result<(), DomainError> {
        panic!("PanicRefreshSessionRepository called")
    }
    async fn revoke_all_for_user(&self, _: &UserId) -> Result<(), DomainError> {
        panic!("PanicRefreshSessionRepository called")
    }
    async fn delete_expired(&self) -> Result<u64, DomainError> {
        panic!("PanicRefreshSessionRepository called")
    }
}

pub struct PanicImportProfileRepository;

#[async_trait]
impl ImportProfileRepository for PanicImportProfileRepository {
    async fn save(&self, _: &ImportProfile) -> Result<(), DomainError> {
        panic!("PanicImportProfileRepository called")
    }
    async fn list_for_user(&self, _: &UserId) -> Result<Vec<ImportProfile>, DomainError> {
        panic!("PanicImportProfileRepository called")
    }
    async fn get(
        &self,
        _: &ImportProfileId,
        _: &UserId,
    ) -> Result<Option<ImportProfile>, DomainError> {
        panic!("PanicImportProfileRepository called")
    }
    async fn delete(&self, _: &ImportProfileId) -> Result<(), DomainError> {
        panic!("PanicImportProfileRepository called")
    }
}

pub struct PanicMovieProfileRepository;

#[async_trait]
impl MovieProfileRepository for PanicMovieProfileRepository {
    async fn upsert(&self, _: &MovieProfile) -> Result<(), DomainError> {
        panic!("PanicMovieProfileRepository called")
    }
    async fn get_by_movie_id(&self, _: &MovieId) -> Result<Option<MovieProfile>, DomainError> {
        panic!("PanicMovieProfileRepository called")
    }
    async fn list_stale(&self) -> Result<Vec<(MovieId, String)>, DomainError> {
        panic!("PanicMovieProfileRepository called")
    }
}

pub struct PanicPersonCommand;

#[async_trait]
impl PersonCommand for PanicPersonCommand {
    async fn upsert_batch(&self, _: &[Person]) -> Result<(), DomainError> {
        panic!("PanicPersonCommand called")
    }
    async fn backfill_from_credits_batch(&self, _: u32) -> Result<(u64, bool), DomainError> {
        panic!("PanicPersonCommand called")
    }
    async fn update_enrichment(
        &self,
        _: &PersonId,
        _: &PersonEnrichmentData,
    ) -> Result<(), DomainError> {
        panic!("PanicPersonCommand called")
    }
}

pub struct PanicPersonQuery;

#[async_trait]
impl PersonQuery for PanicPersonQuery {
    async fn get_by_id(&self, _: &PersonId) -> Result<Option<Person>, DomainError> {
        panic!("PanicPersonQuery called")
    }
    async fn get_by_external_id(
        &self,
        _: &ExternalPersonId,
    ) -> Result<Option<Person>, DomainError> {
        panic!("PanicPersonQuery called")
    }
    async fn get_credits(&self, _: &PersonId) -> Result<PersonCredits, DomainError> {
        panic!("PanicPersonQuery called")
    }
    async fn list_orphaned_persons(&self) -> Result<Vec<PersonId>, DomainError> {
        panic!("PanicPersonQuery called")
    }
    async fn list_page(&self, _: u32, _: u32) -> Result<Vec<Person>, DomainError> {
        panic!("PanicPersonQuery called")
    }
}

pub struct PanicSearchPort;

#[async_trait]
impl SearchPort for PanicSearchPort {
    async fn search(&self, _: &SearchQuery) -> Result<SearchResults, DomainError> {
        Ok(SearchResults {
            movies: Paginated {
                items: vec![],
                total_count: 0,
                limit: 10,
                offset: 0,
            },
            people: Paginated {
                items: vec![],
                total_count: 0,
                limit: 10,
                offset: 0,
            },
        })
    }
}

pub struct PanicSearchCommand;

#[async_trait]
impl SearchCommand for PanicSearchCommand {
    async fn index(&self, _: IndexableDocument) -> Result<(), DomainError> {
        panic!("PanicSearchCommand called")
    }
    async fn remove(&self, _: EntityType, _: &str) -> Result<(), DomainError> {
        panic!("PanicSearchCommand called")
    }
}

pub struct PanicPosterFetcher;

#[async_trait]
impl PosterFetcherClient for PanicPosterFetcher {
    async fn fetch_poster_bytes(&self, _: &PosterUrl) -> Result<Vec<u8>, DomainError> {
        panic!("PanicPosterFetcher called")
    }
}

pub struct PanicDiaryExporter;

impl DiaryExporter for PanicDiaryExporter {
    fn stream_entries(
        &self,
        _stream: futures::stream::BoxStream<'static, Result<DiaryEntry, DomainError>>,
        _format: ExportFormat,
    ) -> futures::stream::BoxStream<'static, Result<bytes::Bytes, DomainError>> {
        panic!("PanicDiaryExporter called")
    }
}

pub struct PanicDocumentParser;

impl DocumentParser for PanicDocumentParser {
    fn parse(&self, _: &[u8], _: FileFormat) -> Result<ParsedFile, ImportError> {
        panic!("PanicDocumentParser called")
    }
    fn apply_mapping(&self, _: &ParsedFile, _: &[FieldMapping]) -> Vec<AnnotatedRow> {
        panic!("PanicDocumentParser called")
    }
}

pub struct PanicWatchlistRepository;

#[async_trait]
impl WatchlistRepository for PanicWatchlistRepository {
    async fn add(&self, _: &WatchlistEntry) -> Result<(), DomainError> {
        panic!("PanicWatchlistRepository called")
    }
    async fn remove(&self, _: &UserId, _: &MovieId) -> Result<(), DomainError> {
        panic!("PanicWatchlistRepository called")
    }
    async fn remove_if_present(&self, _: &UserId, _: &MovieId) -> Result<bool, DomainError> {
        panic!("PanicWatchlistRepository called")
    }
    async fn get_for_user(
        &self,
        _: &UserId,
        _: &PageParams,
    ) -> Result<Paginated<WatchlistWithMovie>, DomainError> {
        panic!("PanicWatchlistRepository called")
    }
    async fn contains(&self, _: &UserId, _: &MovieId) -> Result<bool, DomainError> {
        panic!("PanicWatchlistRepository called")
    }
}

pub struct PanicRemoteWatchlistRepository;

#[async_trait]
impl crate::ports::RemoteWatchlistRepository for PanicRemoteWatchlistRepository {
    async fn save(&self, _: crate::models::RemoteWatchlistEntry) -> Result<(), DomainError> {
        panic!("PanicRemoteWatchlistRepository called")
    }
    async fn remove_by_ap_id(&self, _: &str, _: &str) -> Result<(), DomainError> {
        panic!("PanicRemoteWatchlistRepository called")
    }
    async fn get_by_actor_url(
        &self,
        _: &str,
    ) -> Result<Vec<crate::models::RemoteWatchlistEntry>, DomainError> {
        panic!("PanicRemoteWatchlistRepository called")
    }
    async fn remove_all_by_actor(&self, _: &str) -> Result<(), DomainError> {
        panic!("PanicRemoteWatchlistRepository called")
    }
    async fn get_by_derived_uuid(
        &self,
        _: uuid::Uuid,
    ) -> Result<Vec<crate::models::RemoteWatchlistEntry>, DomainError> {
        panic!("PanicRemoteWatchlistRepository called")
    }
}

pub struct PanicProfileFieldsRepo;

#[async_trait]
impl UserProfileFieldsRepository for PanicProfileFieldsRepo {
    async fn get_fields(
        &self,
        _: &UserId,
    ) -> Result<Vec<crate::models::ProfileField>, DomainError> {
        panic!("PanicProfileFieldsRepo called")
    }
    async fn set_fields(
        &self,
        _: &UserId,
        _: Vec<crate::models::ProfileField>,
    ) -> Result<(), DomainError> {
        panic!("PanicProfileFieldsRepo called")
    }
}

pub struct PanicFederationAdminQuery;

#[async_trait]
impl crate::ports::FederationAdminQuery for PanicFederationAdminQuery {
    async fn list_all_followed_remote_actors(&self) -> Result<Vec<RemoteActorInfo>, DomainError> {
        panic!("PanicFederationAdminQuery called")
    }
}

pub struct PanicFederatedProfileQuery;

#[async_trait]
impl crate::ports::FederatedProfileQuery for PanicFederatedProfileQuery {
    async fn get_federated_profile(
        &self,
        _: uuid::Uuid,
    ) -> Result<Option<crate::models::FederatedProfile>, DomainError> {
        panic!("PanicFederatedProfileQuery called")
    }
}

pub struct PanicWatchEventCommand;

#[async_trait]
impl crate::ports::WatchEventCommand for PanicWatchEventCommand {
    async fn save(&self, _: &crate::models::WatchEvent) -> Result<(), DomainError> {
        panic!("PanicWatchEventCommand called")
    }
    async fn update_status(
        &self,
        _: &crate::value_objects::WatchEventId,
        _: crate::models::WatchEventStatus,
    ) -> Result<(), DomainError> {
        panic!("PanicWatchEventCommand called")
    }
    async fn update_status_batch(
        &self,
        _: &[crate::value_objects::WatchEventId],
        _: crate::models::WatchEventStatus,
    ) -> Result<u64, DomainError> {
        panic!("PanicWatchEventCommand called")
    }
    async fn delete_non_pending_older_than(
        &self,
        _: chrono::NaiveDateTime,
    ) -> Result<u64, DomainError> {
        panic!("PanicWatchEventCommand called")
    }
}

pub struct PanicWatchEventQuery;

#[async_trait]
impl crate::ports::WatchEventQuery for PanicWatchEventQuery {
    async fn list_pending(
        &self,
        _: &UserId,
    ) -> Result<Vec<crate::models::WatchEvent>, DomainError> {
        panic!("PanicWatchEventQuery called")
    }
    async fn get_by_id(
        &self,
        _: &crate::value_objects::WatchEventId,
    ) -> Result<Option<crate::models::WatchEvent>, DomainError> {
        panic!("PanicWatchEventQuery called")
    }
    async fn get_by_ids(
        &self,
        _: &[crate::value_objects::WatchEventId],
    ) -> Result<Vec<crate::models::WatchEvent>, DomainError> {
        panic!("PanicWatchEventQuery called")
    }
    async fn find_duplicate(
        &self,
        _: &UserId,
        _: &str,
        _: chrono::NaiveDateTime,
    ) -> Result<bool, DomainError> {
        panic!("PanicWatchEventQuery called")
    }
}

pub struct PanicWebhookTokenRepository;

#[async_trait]
impl crate::ports::WebhookTokenRepository for PanicWebhookTokenRepository {
    async fn save(&self, _: &crate::models::WebhookToken) -> Result<(), DomainError> {
        panic!("PanicWebhookTokenRepository called")
    }
    async fn find_by_token_hash(
        &self,
        _: &str,
    ) -> Result<Option<crate::models::WebhookToken>, DomainError> {
        panic!("PanicWebhookTokenRepository called")
    }
    async fn list_by_user(
        &self,
        _: &UserId,
    ) -> Result<Vec<crate::models::WebhookToken>, DomainError> {
        panic!("PanicWebhookTokenRepository called")
    }
    async fn delete(
        &self,
        _: &crate::value_objects::WebhookTokenId,
        _: &UserId,
    ) -> Result<(), DomainError> {
        panic!("PanicWebhookTokenRepository called")
    }
    async fn touch_last_used(
        &self,
        _: &crate::value_objects::WebhookTokenId,
    ) -> Result<(), DomainError> {
        panic!("PanicWebhookTokenRepository called")
    }
}
