import { Injectable } from '@nestjs/common';
import { PrismaService } from '../prisma/prisma.service';
import {
  CoManagedWalletSessionRepository,
} from '../../../domain/repositories/co-managed-wallet.repository';
import { CoManagedWalletSessionEntity } from '../../../domain/entities/co-managed-wallet.entity';
import { WalletSessionStatus } from '../../../domain/enums/wallet-session-status.enum';
import { CoManagedWalletMapper } from '../mappers/co-managed-wallet.mapper';

@Injectable()
export class CoManagedWalletSessionRepositoryImpl implements CoManagedWalletSessionRepository {
  constructor(
    private readonly prisma: PrismaService,
    private readonly mapper: CoManagedWalletMapper,
  ) {}

  async save(entity: CoManagedWalletSessionEntity): Promise<CoManagedWalletSessionEntity> {
    const data = this.mapper.sessionToPersistence(entity);

    const saved = await this.prisma.coManagedWalletSession.upsert({
      where: { id: entity.id },
      create: {
        ...data,
        createdAt: entity.createdAt,
        updatedAt: entity.updatedAt,
      },
      update: {
        ...data,
        updatedAt: new Date(),
      },
    });

    return this.mapper.sessionToDomain(saved);
  }

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

    if (!session) {
      return null;
    }

    return this.mapper.sessionToDomain(session);
  }

  async findByInviteCode(inviteCode: string): Promise<CoManagedWalletSessionEntity | null> {
    const session = await this.prisma.coManagedWalletSession.findUnique({
      where: { inviteCode },
    });

    if (!session) {
      return null;
    }

    return this.mapper.sessionToDomain(session);
  }

  async findByCreatedBy(
    createdBy: string,
    status?: WalletSessionStatus,
  ): Promise<CoManagedWalletSessionEntity[]> {
    const sessions = await this.prisma.coManagedWalletSession.findMany({
      where: {
        createdBy,
        ...(status && { status }),
      },
      orderBy: { createdAt: 'desc' },
    });

    return sessions.map((s) => this.mapper.sessionToDomain(s));
  }

  async findAll(params: {
    page: number;
    pageSize: number;
    status?: WalletSessionStatus;
  }): Promise<{
    items: CoManagedWalletSessionEntity[];
    total: number;
  }> {
    const where = params.status ? { status: params.status } : {};

    const [sessions, total] = await Promise.all([
      this.prisma.coManagedWalletSession.findMany({
        where,
        skip: (params.page - 1) * params.pageSize,
        take: params.pageSize,
        orderBy: { createdAt: 'desc' },
      }),
      this.prisma.coManagedWalletSession.count({ where }),
    ]);

    return {
      items: sessions.map((s) => this.mapper.sessionToDomain(s)),
      total,
    };
  }

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