import {
  Injectable,
  NotFoundException,
  ForbiddenException,
  BadRequestException,
  ConflictException,
} from '@nestjs/common';
import { InjectRepository } from '@nestjs/typeorm';
import { Repository } from 'typeorm';
import { Family } from '../../database/entities/family.entity';
import {
  FamilyMember,
  FamilyRole,
} from '../../database/entities/family-member.entity';
import { User } from '../../database/entities/user.entity';
import { InviteFamilyMemberDto } from './dto/invite-family-member.dto';
import { JoinFamilyDto } from './dto/join-family.dto';

@Injectable()
export class FamiliesService {
  constructor(
    @InjectRepository(Family)
    private familyRepository: Repository<Family>,
    @InjectRepository(FamilyMember)
    private familyMemberRepository: Repository<FamilyMember>,
    @InjectRepository(User)
    private userRepository: Repository<User>,
  ) {}

  async inviteMember(
    userId: string,
    familyId: string,
    inviteDto: InviteFamilyMemberDto,
  ): Promise<{ shareCode: string; expiresAt: Date }> {
    // Verify user is a member with invite permissions
    const membership = await this.familyMemberRepository.findOne({
      where: { userId, familyId },
    });

    if (!membership) {
      throw new ForbiddenException('You are not a member of this family');
    }

    if (!membership.permissions['canInviteMembers']) {
      throw new ForbiddenException(
        'You do not have permission to invite members to this family',
      );
    }

    // Get family
    const family = await this.familyRepository.findOne({
      where: { id: familyId },
      relations: ['members'],
    });

    if (!family) {
      throw new NotFoundException('Family not found');
    }

    // Check family size limit (max 10 members as per design)
    if (family.members && family.members.length >= 10) {
      throw new BadRequestException(
        'Family has reached maximum member limit (10)',
      );
    }

    // Check if user is already invited/member
    const invitedUser = await this.userRepository.findOne({
      where: { email: inviteDto.email },
    });

    if (invitedUser) {
      const existingMember = await this.familyMemberRepository.findOne({
        where: { userId: invitedUser.id, familyId },
      });

      if (existingMember) {
        throw new ConflictException('User is already a member of this family');
      }
    }

    // For now, return the family's share code
    // In production, you'd want to create invitation records with expiry
    return {
      shareCode: family.shareCode,
      expiresAt: new Date(Date.now() + 7 * 24 * 60 * 60 * 1000), // 7 days
    };
  }

  async joinFamily(
    userId: string,
    joinDto: JoinFamilyDto,
  ): Promise<FamilyMember> {
    // Find family by share code
    const family = await this.familyRepository.findOne({
      where: { shareCode: joinDto.shareCode },
      relations: ['members'],
    });

    if (!family) {
      throw new NotFoundException('Invalid share code');
    }

    // Check if user is already a member
    const existingMember = await this.familyMemberRepository.findOne({
      where: { userId, familyId: family.id },
    });

    if (existingMember) {
      throw new ConflictException('You are already a member of this family');
    }

    // Check family size limit
    if (family.members && family.members.length >= 10) {
      throw new BadRequestException(
        'Family has reached maximum member limit (10)',
      );
    }

    // Add user as a viewer by default (lowest permissions)
    const newMember = this.familyMemberRepository.create({
      userId,
      familyId: family.id,
      role: FamilyRole.VIEWER,
      permissions: {
        canAddChildren: false,
        canEditChildren: false,
        canLogActivities: true,
        canViewReports: true,
        canInviteMembers: false,
      },
    });

    return await this.familyMemberRepository.save(newMember);
  }

  async getFamily(userId: string, familyId: string): Promise<Family> {
    // Verify user is a member
    const membership = await this.familyMemberRepository.findOne({
      where: { userId, familyId },
    });

    if (!membership) {
      throw new ForbiddenException('You are not a member of this family');
    }

    const family = await this.familyRepository.findOne({
      where: { id: familyId },
      relations: ['members', 'members.user', 'children'],
    });

    if (!family) {
      throw new NotFoundException('Family not found');
    }

    return family;
  }

  async getFamilyMembers(
    userId: string,
    familyId: string,
  ): Promise<FamilyMember[]> {
    // Verify user is a member
    const membership = await this.familyMemberRepository.findOne({
      where: { userId, familyId },
    });

    if (!membership) {
      throw new ForbiddenException('You are not a member of this family');
    }

    return await this.familyMemberRepository.find({
      where: { familyId },
      relations: ['user'],
      order: { joinedAt: 'ASC' },
    });
  }

  async updateMemberRole(
    userId: string,
    familyId: string,
    targetUserId: string,
    role: FamilyRole,
  ): Promise<FamilyMember> {
    // Verify user has admin permissions
    const membership = await this.familyMemberRepository.findOne({
      where: { userId, familyId },
    });

    if (!membership || membership.role !== FamilyRole.PARENT) {
      throw new ForbiddenException('Only parents can update member roles');
    }

    // Get target member
    const targetMember = await this.familyMemberRepository.findOne({
      where: { userId: targetUserId, familyId },
    });

    if (!targetMember) {
      throw new NotFoundException('Family member not found');
    }

    // Update role and permissions based on role
    targetMember.role = role;

    switch (role) {
      case FamilyRole.PARENT:
        targetMember.permissions = {
          canAddChildren: true,
          canEditChildren: true,
          canLogActivities: true,
          canViewReports: true,
          canInviteMembers: true,
        };
        break;
      case FamilyRole.CAREGIVER:
        targetMember.permissions = {
          canAddChildren: false,
          canEditChildren: true,
          canLogActivities: true,
          canViewReports: true,
          canInviteMembers: false,
        };
        break;
      case FamilyRole.VIEWER:
        targetMember.permissions = {
          canAddChildren: false,
          canEditChildren: false,
          canLogActivities: false,
          canViewReports: true,
          canInviteMembers: false,
        };
        break;
      default:
        throw new BadRequestException('Invalid role');
    }

    return await this.familyMemberRepository.save(targetMember);
  }

  async removeMember(
    userId: string,
    familyId: string,
    targetUserId: string,
  ): Promise<void> {
    // Verify user has admin permissions
    const membership = await this.familyMemberRepository.findOne({
      where: { userId, familyId },
    });

    if (!membership || membership.role !== FamilyRole.PARENT) {
      throw new ForbiddenException('Only parents can remove members');
    }

    // Cannot remove yourself if you're the only parent
    if (userId === targetUserId) {
      const parentCount = await this.familyMemberRepository.count({
        where: { familyId, role: FamilyRole.PARENT },
      });

      if (parentCount <= 1) {
        throw new BadRequestException(
          'Cannot remove yourself as the only parent',
        );
      }
    }

    // Remove member
    const targetMember = await this.familyMemberRepository.findOne({
      where: { userId: targetUserId, familyId },
    });

    if (!targetMember) {
      throw new NotFoundException('Family member not found');
    }

    await this.familyMemberRepository.remove(targetMember);
  }
}
