import {
  Injectable,
  CanActivate,
  ExecutionContext,
  ForbiddenException,
  BadRequestException,
  Inject,
} from '@nestjs/common';
import { Reflector } from '@nestjs/core';
import { InjectRepository } from '@nestjs/typeorm';
import { Repository } from 'typeorm';
import { FamilyMember, FamilyRole } from '../../database/entities/family-member.entity';
import { SetMetadata } from '@nestjs/common';

/**
 * Decorator to specify required family roles for an endpoint
 *
 * Usage:
 * @RequireFamilyRole('parent')
 * @RequireFamilyRole('parent', 'guest')
 */
export const RequireFamilyRole = (...roles: string[]) =>
  SetMetadata('familyRoles', roles);

/**
 * FamilyRoleGuard - Enforces family role permissions
 *
 * This guard checks if a user has the required role within a specific family.
 * It should be used after JwtAuthGuard.
 *
 * Usage:
 * @UseGuards(JwtAuthGuard, FamilyRoleGuard)
 * @RequireFamilyRole('parent')
 * async updateChild() { ... }
 */
@Injectable()
export class FamilyRoleGuard implements CanActivate {
  constructor(
    private reflector: Reflector,
    @InjectRepository(FamilyMember)
    private familyMemberRepository: Repository<FamilyMember>,
  ) {}

  async canActivate(context: ExecutionContext): Promise<boolean> {
    // Get required roles from decorator
    const requiredRoles = this.reflector.get<string[]>(
      'familyRoles',
      context.getHandler(),
    );

    // If no roles specified, allow access
    if (!requiredRoles || requiredRoles.length === 0) {
      return true;
    }

    const request = context.switchToHttp().getRequest();
    const user = request.user;

    if (!user || !user.id) {
      throw new ForbiddenException('User not authenticated');
    }

    // Extract familyId from params or body
    const familyId =
      request.params.familyId ||
      request.body?.familyId ||
      request.query?.familyId;

    if (!familyId) {
      throw new BadRequestException(
        'Family ID is required for this operation',
      );
    }

    // Check user's role in this family
    const membership = await this.familyMemberRepository.findOne({
      where: {
        userId: user.id,
        familyId: familyId,
      },
    });

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

    // Check if user's role matches required roles
    if (!requiredRoles.includes(membership.role)) {
      throw new ForbiddenException(
        `This action requires one of the following roles: ${requiredRoles.join(', ')}. Your current role: ${membership.role}`,
      );
    }

    // Check if access has expired (for guest accounts)
    if (membership.accessExpiresAt) {
      const now = new Date();
      if (now > membership.accessExpiresAt) {
        throw new ForbiddenException(
          'Your access to this family has expired',
        );
      }
    }

    // Attach membership info to request for use in controllers
    request.familyMembership = membership;
    request.familyRole = membership.role;

    return true;
  }
}
