use crate::{AppService, error::AppError};
use chrono::Utc;
use models::users::user_relation;
use sea_orm::*;
use serde::{Deserialize, Serialize};
use session::Session;
use uuid::Uuid;

#[derive(Deserialize, Serialize, Clone, Debug, utoipa::ToSchema)]
pub struct SubscriptionInfo {
    pub id: i64,
    pub user_uid: Uuid,
    pub target_uid: Uuid,
    pub subscribed_at: chrono::DateTime<Utc>,
    pub is_active: bool,
}

#[derive(serde::Serialize, Clone, Debug, utoipa::ToSchema)]
pub struct UserCard {
    pub user_uid: Uuid,
    pub username: String,
    pub display_name: Option<String>,
    pub avatar_url: Option<String>,
    pub is_following_me: bool,
}

impl From<user_relation::Model> for SubscriptionInfo {
    fn from(sub: user_relation::Model) -> Self {
        SubscriptionInfo {
            id: sub.id,
            user_uid: sub.user,
            target_uid: sub.target,
            subscribed_at: sub.created_at,
            is_active: true, // user_relation doesn't have is_active, we treat follow as active
        }
    }
}

impl AppService {
    pub async fn user_subscribe_target(
        &self,
        context: Session,
        target: String,
    ) -> Result<(), AppError> {
        let user_uid = context.user().ok_or(AppError::Unauthorized)?;

        let target_user = self.utils_find_user_by_username(target).await?;
        let target_uid = target_user.uid;

        let existing = user_relation::Entity::find()
            .filter(user_relation::Column::User.eq(user_uid))
            .filter(user_relation::Column::Target.eq(target_uid))
            .filter(user_relation::Column::RelationType.eq("follow"))
            .one(&self.db)
            .await?;

        if existing.is_some() {
            return Err(AppError::NotFound("Already subscribed".to_string()));
        }

        let subscription = user_relation::ActiveModel {
            user: Set(user_uid),
            target: Set(target_uid),
            relation_type: Set("follow".to_string()),
            created_at: Set(Utc::now()),
            ..Default::default()
        };

        subscription.insert(&self.db).await?;

        Ok(())
    }

    pub async fn user_unsubscribe_target(
        &self,
        context: Session,
        target: String,
    ) -> Result<(), AppError> {
        let user_uid = context.user().ok_or(AppError::Unauthorized)?;

        let target_user = self.utils_find_user_by_username(target).await?;
        let target_uid = target_user.uid;

        user_relation::Entity::delete_many()
            .filter(user_relation::Column::User.eq(user_uid))
            .filter(user_relation::Column::Target.eq(target_uid))
            .filter(user_relation::Column::RelationType.eq("follow"))
            .exec(&self.db)
            .await?;

        Ok(())
    }

    pub async fn user_is_subscribed_to_target(
        &self,
        context: Session,
        target: String,
    ) -> Result<bool, AppError> {
        let user_uid = context.user().ok_or(AppError::Unauthorized)?;

        let target_user = self.utils_find_user_by_username(target).await?;
        let target_uid = target_user.uid;

        let subscription = user_relation::Entity::find()
            .filter(user_relation::Column::User.eq(user_uid))
            .filter(user_relation::Column::Target.eq(target_uid))
            .filter(user_relation::Column::RelationType.eq("follow"))
            .one(&self.db)
            .await?;

        Ok(subscription.is_some())
    }

    pub async fn user_get_subscribers(
        &self,
        _context: Session,
        target: String,
    ) -> Result<Vec<SubscriptionInfo>, AppError> {
        let target_user = self.utils_find_user_by_username(target).await?;
        let target_uid = target_user.uid;

        let subscribers = user_relation::Entity::find()
            .filter(user_relation::Column::Target.eq(target_uid))
            .filter(user_relation::Column::RelationType.eq("follow"))
            .order_by_desc(user_relation::Column::CreatedAt)
            .all(&self.db)
            .await?;

        Ok(subscribers
            .into_iter()
            .map(SubscriptionInfo::from)
            .collect())
    }

    pub async fn user_get_subscription_count(
        &self,
        _context: Session,
        username: String,
    ) -> Result<u64, AppError> {
        let user_uid = self.utils_find_user_by_username(username).await?.uid;
        let count = user_relation::Entity::find()
            .filter(user_relation::Column::User.eq(user_uid))
            .filter(user_relation::Column::RelationType.eq("follow"))
            .count(&self.db)
            .await?;

        Ok(count)
    }

    pub async fn user_get_subscriber_count(
        &self,
        _context: Session,
        target: String,
    ) -> Result<u64, AppError> {
        let target_user = self.utils_find_user_by_username(target).await?;
        let target_uid = target_user.uid;

        let count = user_relation::Entity::find()
            .filter(user_relation::Column::Target.eq(target_uid))
            .filter(user_relation::Column::RelationType.eq("follow"))
            .count(&self.db)
            .await?;

        Ok(count)
    }

    pub async fn user_get_following_list(
        &self,
        context: Session,
        username: String,
    ) -> Result<Vec<UserCard>, AppError> {
        let target_user = self.utils_find_user_by_username(username).await?;
        let target_uid = target_user.uid;
        let current_uid = context.user();

        let following = user_relation::Entity::find()
            .filter(user_relation::Column::User.eq(target_uid))
            .filter(user_relation::Column::RelationType.eq("follow"))
            .order_by_desc(user_relation::Column::CreatedAt)
            .all(&self.db)
            .await?;

        let followed_uids: Vec<Uuid> = following.iter().map(|f| f.target).collect();

        let followed_users: std::collections::HashMap<Uuid, models::users::user::Model> = models::users::user::Entity::find()
            .filter(models::users::user::Column::Uid.is_in(followed_uids.clone()))
            .all(&self.db)
            .await?
            .into_iter()
            .map(|u| (u.uid, u))
            .collect();

        // If current user is logged in, check who they also follow
        let current_follows: std::collections::HashSet<Uuid> = if let Some(uid) = current_uid {
            user_relation::Entity::find()
                .filter(user_relation::Column::User.eq(uid))
                .filter(user_relation::Column::Target.is_in(followed_uids.clone()))
                .filter(user_relation::Column::RelationType.eq("follow"))
                .select_only()
                .column(user_relation::Column::Target)
                .into_tuple::<Uuid>()
                .all(&self.db)
                .await?
                .into_iter()
                .collect()
        } else {
            std::collections::HashSet::new()
        };

        let mut cards: Vec<UserCard> = Vec::new();
        for rel in following {
            if let Some(user) = followed_users.get(&rel.target) {
                cards.push(UserCard {
                    user_uid: user.uid,
                    username: user.username.clone(),
                    display_name: user.display_name.clone(),
                    avatar_url: user.avatar_url.clone(),
                    is_following_me: current_follows.contains(&user.uid),
                });
            }
        }

        Ok(cards)
    }
}
