import { Injectable } from '@nestjs/common';
import { AppVersionRepository } from '@/domain/repositories/app-version.repository';
import { AppVersion } from '@/domain/entities/app-version.entity';
import { Platform } from '@/domain/enums/platform.enum';
import { VersionCode } from '@/domain/value-objects/version-code.vo';
import { PrismaService } from '../prisma/prisma.service';
import { AppVersionMapper } from '../mappers/app-version.mapper';

@Injectable()
export class AppVersionRepositoryImpl implements AppVersionRepository {
  constructor(
    private readonly prisma: PrismaService,
    private readonly mapper: AppVersionMapper,
  ) {}

  async save(appVersion: AppVersion): Promise<AppVersion> {
    const data = this.mapper.toPersistence(appVersion);
    const created = await this.prisma.appVersion.create({
      data: {
        ...data,
        createdAt: appVersion.createdAt,
        updatedAt: appVersion.updatedAt,
      },
    });

    return this.mapper.toDomain(created);
  }

  async findById(id: string): Promise<AppVersion | null> {
    const found = await this.prisma.appVersion.findUnique({ where: { id } });
    return found ? this.mapper.toDomain(found) : null;
  }

  async findLatestByPlatform(platform: Platform): Promise<AppVersion | null> {
    const found = await this.prisma.appVersion.findFirst({
      where: { platform, isEnabled: true },
      orderBy: { versionCode: 'desc' },
    });
    return found ? this.mapper.toDomain(found) : null;
  }

  async findAllByPlatform(platform: Platform, includeDisabled = false): Promise<AppVersion[]> {
    const results = await this.prisma.appVersion.findMany({
      where: includeDisabled ? { platform } : { platform, isEnabled: true },
      orderBy: { versionCode: 'desc' },
    });
    return results.map((r) => this.mapper.toDomain(r));
  }

  async findByPlatformAndVersionCode(
    platform: Platform,
    versionCode: VersionCode,
  ): Promise<AppVersion | null> {
    const found = await this.prisma.appVersion.findFirst({
      where: { platform, versionCode: versionCode.value },
    });
    return found ? this.mapper.toDomain(found) : null;
  }

  async update(id: string, updates: Partial<AppVersion>): Promise<AppVersion> {
    const data: any = {};

    if (updates.versionName) data.versionName = updates.versionName.value;
    if (updates.buildNumber) data.buildNumber = updates.buildNumber.value;
    if (updates.downloadUrl) data.downloadUrl = updates.downloadUrl.value;
    if (updates.fileSize !== undefined) data.fileSize = updates.fileSize.bytes;
    if (updates.fileSha256) data.fileSha256 = updates.fileSha256.value;
    if (updates.changelog) data.changelog = updates.changelog.value;
    if (updates.isForceUpdate !== undefined) data.isForceUpdate = updates.isForceUpdate;
    if (updates.minOsVersion !== undefined) data.minOsVersion = updates.minOsVersion?.value ?? null;
    if (updates.releaseDate !== undefined) data.releaseDate = updates.releaseDate;
    if (updates.updatedBy !== undefined) data.updatedBy = updates.updatedBy;

    data.updatedAt = new Date();

    const updated = await this.prisma.appVersion.update({
      where: { id },
      data,
    });

    return this.mapper.toDomain(updated);
  }

  async toggleEnabled(id: string, isEnabled: boolean): Promise<void> {
    await this.prisma.appVersion.update({
      where: { id },
      data: { isEnabled, updatedAt: new Date() },
    });
  }

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