import {
  Injectable,
  NotFoundException,
  ForbiddenException,
  BadRequestException,
  Logger,
} from '@nestjs/common';
import { InjectRepository } from '@nestjs/typeorm';
import { Repository, IsNull } from 'typeorm';
import { Child } from '../../database/entities/child.entity';
import { FamilyMember } from '../../database/entities/family-member.entity';
import { CreateChildDto } from './dto/create-child.dto';
import { UpdateChildDto } from './dto/update-child.dto';

@Injectable()
export class ChildrenService {
  private readonly logger = new Logger(ChildrenService.name);
  private readonly CHILD_COLORS = [
    '#FF6B9D', // Pink
    '#4ECDC4', // Teal
    '#FFD93D', // Yellow
    '#95E1D3', // Mint
    '#C7CEEA', // Lavender
    '#FF8C42', // Orange
    '#A8E6CF', // Green
    '#B8B8FF', // Purple
  ];

  constructor(
    @InjectRepository(Child)
    private childRepository: Repository<Child>,
    @InjectRepository(FamilyMember)
    private familyMemberRepository: Repository<FamilyMember>,
  ) {}

  async create(
    userId: string,
    familyId: string,
    createChildDto: CreateChildDto,
  ): Promise<Child> {
    // Verify user has permission to add children to this family
    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['canAddChildren']) {
      throw new ForbiddenException(
        'You do not have permission to add children to this family',
      );
    }

    // Get family's existing children count to determine color and sort order
    const existingChildren = await this.childRepository.find({
      where: { familyId, deletedAt: IsNull() },
      order: { createdAt: 'ASC' },
    });

    const sortOrder = existingChildren.length;

    // Use custom color if provided, otherwise auto-assign
    const displayColor = createChildDto.displayColor ||
      this.CHILD_COLORS[sortOrder % this.CHILD_COLORS.length];

    // Create child
    const child = this.childRepository.create({
      ...createChildDto,
      familyId,
      birthDate: new Date(createChildDto.birthDate),
      displayColor,
      sortOrder,
    });

    return await this.childRepository.save(child);
  }

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

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

    // Return only active (non-deleted) children
    return await this.childRepository.find({
      where: {
        familyId,
        deletedAt: IsNull(),
      },
      order: {
        birthDate: 'DESC', // Youngest first
      },
    });
  }

  async findOne(userId: string, id: string): Promise<Child> {
    const child = await this.childRepository.findOne({
      where: { id, deletedAt: IsNull() },
      relations: ['family'],
    });

    if (!child) {
      throw new NotFoundException('Child not found');
    }

    // Verify user is a member of the child's family
    const membership = await this.familyMemberRepository.findOne({
      where: { userId, familyId: child.familyId },
    });

    if (!membership) {
      throw new ForbiddenException('You do not have access to this child');
    }

    return child;
  }

  async update(
    userId: string,
    id: string,
    updateChildDto: UpdateChildDto,
  ): Promise<Child> {
    const child = await this.childRepository.findOne({
      where: { id, deletedAt: IsNull() },
    });

    if (!child) {
      throw new NotFoundException('Child not found');
    }

    // Verify user has permission to edit children in this family
    const membership = await this.familyMemberRepository.findOne({
      where: { userId, familyId: child.familyId },
    });

    if (!membership) {
      throw new ForbiddenException('You do not have access to this child');
    }

    if (!membership.permissions['canEditChildren']) {
      throw new ForbiddenException(
        'You do not have permission to edit children in this family',
      );
    }

    // Update child
    if (updateChildDto.name !== undefined) {
      child.name = updateChildDto.name;
    }
    if (updateChildDto.birthDate !== undefined) {
      child.birthDate = new Date(updateChildDto.birthDate);
    }
    if (updateChildDto.gender !== undefined) {
      child.gender = updateChildDto.gender;
    }
    if (updateChildDto.photoUrl !== undefined) {
      child.photoUrl = updateChildDto.photoUrl;
    }
    if (updateChildDto.photoAlt !== undefined) {
      child.photoAlt = updateChildDto.photoAlt;
    }
    if (updateChildDto.displayColor !== undefined) {
      child.displayColor = updateChildDto.displayColor;
    }
    if (updateChildDto.nickname !== undefined) {
      child.nickname = updateChildDto.nickname;
    }
    if (updateChildDto.medicalInfo !== undefined) {
      child.medicalInfo = updateChildDto.medicalInfo;
    }

    return await this.childRepository.save(child);
  }

  async remove(userId: string, id: string): Promise<void> {
    const child = await this.childRepository.findOne({
      where: { id, deletedAt: IsNull() },
    });

    if (!child) {
      throw new NotFoundException('Child not found');
    }

    // Verify user has permission to edit children in this family
    const membership = await this.familyMemberRepository.findOne({
      where: { userId, familyId: child.familyId },
    });

    if (!membership) {
      throw new ForbiddenException('You do not have access to this child');
    }

    if (!membership.permissions['canEditChildren']) {
      throw new ForbiddenException(
        'You do not have permission to delete children in this family',
      );
    }

    // Soft delete
    child.deletedAt = new Date();
    await this.childRepository.save(child);
  }

  /**
   * Get children age in months for activity analysis
   */
  async getChildAgeInMonths(childId: string): Promise<number> {
    const child = await this.childRepository.findOne({
      where: { id: childId, deletedAt: IsNull() },
    });

    if (!child) {
      throw new NotFoundException('Child not found');
    }

    const now = new Date();
    const birthDate = new Date(child.birthDate);
    const ageInMonths =
      (now.getFullYear() - birthDate.getFullYear()) * 12 +
      (now.getMonth() - birthDate.getMonth());

    return ageInMonths;
  }

  /**
   * Get all children for a user across all their families
   */
  async findAllForUser(userId: string): Promise<Child[]> {
    this.logger.log(`[findAllForUser] userId: ${userId}`);

    // Get all family memberships for user
    const memberships = await this.familyMemberRepository.find({
      where: { userId },
    });

    this.logger.log(`[findAllForUser] Found ${memberships.length} memberships for user ${userId}: ${memberships.map(m => m.familyId).join(', ')}`);

    if (memberships.length === 0) {
      return [];
    }

    const familyIds = memberships.map((m) => m.familyId);

    // Get all children from user's families
    const children = await this.childRepository
      .createQueryBuilder('child')
      .where('child.familyId IN (:...familyIds)', { familyIds })
      .andWhere('child.deletedAt IS NULL')
      .orderBy('child.birthDate', 'DESC')
      .getMany();

    this.logger.log(`[findAllForUser] Returning ${children.length} children for user ${userId}: ${children.map(c => `${c.name}(${c.familyId})`).join(', ')}`);

    return children;
  }

  /**
   * Get family statistics for multi-child UI decisions
   */
  async getFamilyStatistics(
    userId: string,
    familyId: string,
  ): Promise<{
    totalChildren: number;
    viewMode: 'tabs' | 'cards';
    ageRange: { youngest: number; oldest: number } | null;
    genderDistribution: { male: number; female: number; other: number };
  }> {
    // Verify user has access to family
    const membership = await this.familyMemberRepository.findOne({
      where: { userId, familyId },
    });

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

    const children = await this.findAll(userId, familyId);

    if (children.length === 0) {
      return {
        totalChildren: 0,
        viewMode: 'tabs',
        ageRange: null,
        genderDistribution: { male: 0, female: 0, other: 0 },
      };
    }

    // Calculate ages in months
    const ages = children.map((child) => {
      const now = new Date();
      const birthDate = new Date(child.birthDate);
      return (
        (now.getFullYear() - birthDate.getFullYear()) * 12 +
        (now.getMonth() - birthDate.getMonth())
      );
    });

    // Gender distribution
    const genderDistribution = children.reduce(
      (acc, child) => {
        if (child.gender === 'male') acc.male++;
        else if (child.gender === 'female') acc.female++;
        else acc.other++;
        return acc;
      },
      { male: 0, female: 0, other: 0 },
    );

    return {
      totalChildren: children.length,
      viewMode: children.length <= 3 ? 'tabs' : 'cards',
      ageRange: {
        youngest: Math.min(...ages),
        oldest: Math.max(...ages),
      },
      genderDistribution,
    };
  }

  /**
   * Check if user has access to a specific child
   */
  async userHasAccessToChild(
    userId: string,
    childId: string,
  ): Promise<boolean> {
    const child = await this.childRepository.findOne({
      where: { id: childId, deletedAt: IsNull() },
    });

    if (!child) {
      return false;
    }

    const membership = await this.familyMemberRepository.findOne({
      where: { userId, familyId: child.familyId },
    });

    return !!membership;
  }
}
