import { Injectable } from '@nestjs/common';
import { PrismaService } from '../prisma/prisma.service';
import { AudienceSegmentRepository } from '../../../domain/repositories/audience-segment.repository';
import {
  AudienceSegmentEntity,
  SegmentConditionGroup,
  SegmentUsageType,
} from '../../../domain/entities/audience-segment.entity';

@Injectable()
export class AudienceSegmentRepositoryImpl implements AudienceSegmentRepository {
  constructor(private readonly prisma: PrismaService) {}

  async save(segment: AudienceSegmentEntity): Promise<AudienceSegmentEntity> {
    const data = {
      id: segment.id,
      name: segment.name,
      description: segment.description,
      conditions: segment.conditions as object,
      estimatedUsers: segment.estimatedUsers,
      lastCalculated: segment.lastCalculated,
      usageType: segment.usageType,
      isEnabled: segment.isEnabled,
      createdBy: segment.createdBy,
      updatedAt: new Date(),
    };

    const result = await this.prisma.audienceSegment.upsert({
      where: { id: segment.id },
      create: {
        ...data,
        createdAt: segment.createdAt,
      },
      update: data,
    });

    return this.mapToEntity(result);
  }

  async findById(id: string): Promise<AudienceSegmentEntity | null> {
    const result = await this.prisma.audienceSegment.findUnique({
      where: { id },
    });

    return result ? this.mapToEntity(result) : null;
  }

  async findAll(params?: {
    usageType?: SegmentUsageType;
    isEnabled?: boolean;
    limit?: number;
    offset?: number;
  }): Promise<AudienceSegmentEntity[]> {
    const where: {
      usageType?: SegmentUsageType;
      isEnabled?: boolean;
    } = {};

    if (params?.usageType) {
      where.usageType = params.usageType;
    }
    if (params?.isEnabled !== undefined) {
      where.isEnabled = params.isEnabled;
    }

    const results = await this.prisma.audienceSegment.findMany({
      where,
      take: params?.limit,
      skip: params?.offset,
      orderBy: { createdAt: 'desc' },
    });

    return results.map((r) => this.mapToEntity(r));
  }

  async findByUsageType(
    usageType: SegmentUsageType,
  ): Promise<AudienceSegmentEntity[]> {
    return this.findAll({ usageType, isEnabled: true });
  }

  async count(params?: {
    usageType?: SegmentUsageType;
    isEnabled?: boolean;
  }): Promise<number> {
    const where: {
      usageType?: SegmentUsageType;
      isEnabled?: boolean;
    } = {};

    if (params?.usageType) {
      where.usageType = params.usageType;
    }
    if (params?.isEnabled !== undefined) {
      where.isEnabled = params.isEnabled;
    }

    return this.prisma.audienceSegment.count({ where });
  }

  async delete(id: string): Promise<void> {
    await this.prisma.audienceSegment.delete({
      where: { id },
    });
  }

  async updateEstimatedUsers(id: string, count: number): Promise<void> {
    await this.prisma.audienceSegment.update({
      where: { id },
      data: {
        estimatedUsers: count,
        lastCalculated: new Date(),
        updatedAt: new Date(),
      },
    });
  }

  private mapToEntity(data: {
    id: string;
    name: string;
    description: string | null;
    conditions: unknown;
    estimatedUsers: number | null;
    lastCalculated: Date | null;
    usageType: string;
    isEnabled: boolean;
    createdAt: Date;
    updatedAt: Date;
    createdBy: string;
  }): AudienceSegmentEntity {
    return new AudienceSegmentEntity(
      data.id,
      data.name,
      data.description,
      data.conditions as SegmentConditionGroup,
      data.estimatedUsers,
      data.lastCalculated,
      data.usageType as SegmentUsageType,
      data.isEnabled,
      data.createdAt,
      data.updatedAt,
      data.createdBy,
    );
  }
}
