import { Inject, Injectable, BadRequestException } from '@nestjs/common'
import { UploadVersionCommand } from './upload-version.command'
import { AppVersionRepository, APP_VERSION_REPOSITORY } from '@/domain/repositories/app-version.repository'
import { AppVersion } from '@/domain/entities/app-version.entity'
import { VersionCode } from '@/domain/value-objects/version-code.vo'
import { VersionName } from '@/domain/value-objects/version-name.vo'
import { BuildNumber } from '@/domain/value-objects/build-number.vo'
import { DownloadUrl } from '@/domain/value-objects/download-url.vo'
import { FileSize } from '@/domain/value-objects/file-size.vo'
import { FileSha256 } from '@/domain/value-objects/file-sha256.vo'
import { Changelog } from '@/domain/value-objects/changelog.vo'
import { MinOsVersion } from '@/domain/value-objects/min-os-version.vo'
import { FileStorageService } from '@/infrastructure/storage/file-storage.service'
import { PackageParserService } from '@/infrastructure/parsers/package-parser.service'

@Injectable()
export class UploadVersionHandler {
  constructor(
    @Inject(APP_VERSION_REPOSITORY)
    private readonly appVersionRepository: AppVersionRepository,
    private readonly fileStorageService: FileStorageService,
    private readonly packageParserService: PackageParserService,
  ) {}

  async execute(command: UploadVersionCommand): Promise<AppVersion> {
    // Parse package info from APK/IPA
    const parsedInfo = await this.packageParserService.parsePackage(
      command.fileBuffer,
      command.platform,
    )

    // Determine version info (use provided values or fall back to parsed values)
    const versionCode = command.versionCode ?? parsedInfo?.versionCode
    const versionName = command.versionName ?? parsedInfo?.versionName
    const buildNumber = command.buildNumber ?? versionCode?.toString()
    const minOsVersion = command.minOsVersion ?? parsedInfo?.minSdkVersion

    // Validate required fields
    if (!versionCode) {
      throw new BadRequestException(
        'Unable to detect version code from package. Please provide it manually.',
      )
    }
    if (!versionName) {
      throw new BadRequestException(
        'Unable to detect version name from package. Please provide it manually.',
      )
    }

    // Save the uploaded file
    const uploadResult = await this.fileStorageService.saveFile(
      command.fileBuffer,
      command.originalFilename,
      command.platform,
      versionName,
    )

    // Create value objects
    const versionCodeVO = VersionCode.create(versionCode)
    const versionNameVO = VersionName.create(versionName)
    const buildNumberVO = BuildNumber.create(buildNumber || versionCode.toString())
    const downloadUrl = DownloadUrl.create(uploadResult.url)
    const fileSize = FileSize.create(BigInt(uploadResult.size))
    const fileSha256 = FileSha256.create(uploadResult.sha256)
    const changelog = Changelog.create(command.changelog)
    const minOsVersionVO = minOsVersion ? MinOsVersion.create(minOsVersion) : null

    // Create the app version entity
    const appVersion = AppVersion.create({
      platform: command.platform,
      versionCode: versionCodeVO,
      versionName: versionNameVO,
      buildNumber: buildNumberVO,
      downloadUrl,
      fileSize,
      fileSha256,
      changelog,
      isForceUpdate: command.isForceUpdate,
      minOsVersion: minOsVersionVO,
      releaseDate: command.releaseDate ?? null,
      createdBy: command.createdBy,
    })

    // Save to database
    return await this.appVersionRepository.save(appVersion)
  }
}
