import graphene
import logging
from django.contrib.auth import get_user_model
from graphene_django import DjangoObjectType

from .models import Team as TeamModel, TeamMember as TeamMemberModel, TeamInvitation as TeamInvitationModel, UserProfile

logger = logging.getLogger(__name__)
UserModel = get_user_model()


def _get_or_create_user_with_profile(logto_id: str) -> UserModel:
    user, _ = UserModel.objects.get_or_create(
        username=logto_id,
        defaults={'email': ''}
    )
    profile, _ = UserProfile.objects.get_or_create(
        logto_id=logto_id,
        defaults={'user': user}
    )
    if profile.user_id != user.id:
        profile.user = user
        profile.save(update_fields=['user'])
    return user


class Team(DjangoObjectType):
    id = graphene.String()  # Для совместимости с фронтендом
    ownerId = graphene.String()
    members = graphene.List(lambda: TeamMember)

    class Meta:
        model = TeamModel
        fields = ('uuid', 'name', 'logto_org_id', 'owner', 'status', 'created_at', 'updated_at')

    def resolve_id(self, info):
        return self.uuid

    def resolve_ownerId(self, info):
        if self.owner and hasattr(self.owner, 'profile'):
            return self.owner.profile.logto_id
        return self.owner.username if self.owner else None

    def resolve_members(self, info):
        return self.members.all()


class User(DjangoObjectType):
    id = graphene.String()  # Для совместимости с фронтендом
    firstName = graphene.String()
    lastName = graphene.String()
    phone = graphene.String()
    avatarId = graphene.String()
    createdAt = graphene.String()
    activeTeamId = graphene.String()
    currentTeam = graphene.Field(Team)
    activeTeam = graphene.Field(Team)
    teams = graphene.List(Team)

    class Meta:
        model = UserModel
        fields = ('username', 'first_name', 'last_name', 'email')

    def resolve_id(self, info):
        if hasattr(self, 'profile') and self.profile:
            return self.profile.logto_id
        return self.username

    def resolve_firstName(self, info):
        return self.first_name

    def resolve_lastName(self, info):
        return self.last_name

    def resolve_phone(self, info):
        return getattr(self.profile, 'phone', None)

    def resolve_avatarId(self, info):
        return getattr(self.profile, 'avatar_id', None)

    def resolve_createdAt(self, info):
        return self.date_joined.isoformat() if self.date_joined else None

    def resolve_activeTeamId(self, info):
        return self.profile.active_team.uuid if getattr(self, 'profile', None) and self.profile.active_team else None

    def resolve_currentTeam(self, info):
        return self.profile.active_team if getattr(self, 'profile', None) else None

    def resolve_activeTeam(self, info):
        return self.profile.active_team if getattr(self, 'profile', None) else None

    def resolve_teams(self, info):
        owned_teams = TeamModel.objects.filter(owner=self)
        member_teams = TeamModel.objects.filter(members__user=self)
        return (owned_teams | member_teams).distinct()


class TeamMember(DjangoObjectType):
    userId = graphene.String()

    class Meta:
        model = TeamMemberModel
        fields = ('uuid', 'user', 'role', 'joined_at')

    def resolve_userId(self, info):
        if self.user and hasattr(self.user, 'profile'):
            return self.user.profile.logto_id
        return self.user.username if self.user else None


class TeamInvitation(DjangoObjectType):
    class Meta:
        model = TeamInvitationModel
        fields = ('uuid', 'email', 'role', 'status', 'invited_by', 'expires_at')


class Query(graphene.ObjectType):
    me = graphene.Field(User)
    getTeam = graphene.Field(Team, teamId=graphene.String(required=True))

    def resolve_me(self, info):
        user_id = getattr(info.context, 'user_id', None)
        if not user_id:
            raise Exception("User not authenticated")

        return _get_or_create_user_with_profile(user_id)

    def resolve_getTeam(self, info, teamId):
        try:
            return TeamModel.objects.get(uuid=teamId)
        except TeamModel.DoesNotExist:
            return None


class CreateTeamInput(graphene.InputObjectType):
    name = graphene.String(required=True)


class UpdateUserInput(graphene.InputObjectType):
    firstName = graphene.String()
    lastName = graphene.String()
    phone = graphene.String()
    avatarId = graphene.String()


class CreateTeam(graphene.Mutation):
    class Arguments:
        input = CreateTeamInput(required=True)
        ownerId = graphene.String(required=True)

    team = graphene.Field(Team)

    def mutate(self, info, input, ownerId):
        owner = _get_or_create_user_with_profile(ownerId)

        team = TeamModel.objects.create(
            name=input.name,
            owner=owner,
            status='PENDING_KYC'
        )

        # Добавляем owner как участника команды с ролью OWNER
        TeamMemberModel.objects.create(
            team=team,
            user=owner,
            role='OWNER'
        )

        if hasattr(owner, 'profile') and not owner.profile.active_team:
            owner.profile.active_team = team
            owner.profile.save(update_fields=['active_team'])

        logger.info("Team %s created, waiting for KYC submission", team.uuid)

        return CreateTeam(team=team)


class UpdateUser(graphene.Mutation):
    class Arguments:
        userId = graphene.String(required=True)
        input = UpdateUserInput(required=True)

    id = graphene.String()
    firstName = graphene.String()
    lastName = graphene.String()
    phone = graphene.String()
    avatarId = graphene.String()
    activeTeamId = graphene.String()
    activeTeam = graphene.Field(Team)

    def mutate(self, info, userId, input):
        try:
            user = _get_or_create_user_with_profile(userId)

            if input.firstName is not None:
                user.first_name = input.firstName
            if input.lastName is not None:
                user.last_name = input.lastName
            user.save()

            if hasattr(user, 'profile'):
                if input.phone is not None:
                    user.profile.phone = input.phone
                if input.avatarId is not None:
                    user.profile.avatar_id = input.avatarId
                user.profile.save()

            return UpdateUser(
                id=user.profile.logto_id if hasattr(user, 'profile') else user.username,
                firstName=user.first_name,
                lastName=user.last_name,
                phone=getattr(user.profile, 'phone', None),
                avatarId=getattr(user.profile, 'avatar_id', None),
                activeTeamId=user.profile.active_team.uuid if hasattr(user, 'profile') and user.profile.active_team else None,
                activeTeam=user.profile.active_team if hasattr(user, 'profile') else None
            )
        except Exception as e:
            raise Exception(f"Failed to update user: {str(e)}")


class SwitchTeam(graphene.Mutation):
    class Arguments:
        userId = graphene.String(required=True)
        teamId = graphene.String(required=True)

    user = graphene.Field(User)

    def mutate(self, info, userId, teamId):
        try:
            team = TeamModel.objects.get(uuid=teamId)
            user = _get_or_create_user_with_profile(userId)
            if hasattr(user, 'profile'):
                user.profile.active_team = team
                user.profile.save(update_fields=['active_team'])
            return SwitchTeam(user=user)
        except TeamModel.DoesNotExist:
            raise Exception("Team not found")


class Mutation(graphene.ObjectType):
    createTeam = CreateTeam.Field()
    updateUser = UpdateUser.Field()
    switchTeam = SwitchTeam.Field()


schema = graphene.Schema(query=Query, mutation=Mutation)
