import { Injectable, Logger } from '@nestjs/common'
import { ConfigService } from '@nestjs/config'
import * as fs from 'fs/promises'
import * as path from 'path'
import * as crypto from 'crypto'

export interface FileUploadResult {
  filename: string
  originalName: string
  path: string
  size: number
  sha256: string
  url: string
}

@Injectable()
export class FileStorageService {
  private readonly logger = new Logger(FileStorageService.name)
  private readonly uploadDir: string
  private readonly baseUrl: string

  constructor(private readonly configService: ConfigService) {
    this.uploadDir = this.configService.get<string>('UPLOAD_DIR') || './uploads'
    this.baseUrl = this.configService.get<string>('BASE_URL') || 'http://localhost:3000'
  }

  async ensureUploadDir(): Promise<void> {
    try {
      await fs.access(this.uploadDir)
    } catch {
      await fs.mkdir(this.uploadDir, { recursive: true })
      this.logger.log(`Created upload directory: ${this.uploadDir}`)
    }
  }

  async saveFile(
    buffer: Buffer,
    originalName: string,
    platform: string,
    versionName: string,
  ): Promise<FileUploadResult> {
    await this.ensureUploadDir()

    // Generate unique filename with platform and version info
    const ext = path.extname(originalName)
    const timestamp = Date.now()
    const randomSuffix = crypto.randomBytes(4).toString('hex')
    const filename = `${platform}-${versionName}-${timestamp}-${randomSuffix}${ext}`

    // Calculate SHA256 hash
    const sha256 = crypto.createHash('sha256').update(buffer).digest('hex')

    // Save file
    const filePath = path.join(this.uploadDir, filename)
    await fs.writeFile(filePath, buffer)

    this.logger.log(`Saved file: ${filename} (${buffer.length} bytes, SHA256: ${sha256})`)

    return {
      filename,
      originalName,
      path: filePath,
      size: buffer.length,
      sha256,
      url: `${this.baseUrl}/downloads/${filename}`,
    }
  }

  async deleteFile(filename: string): Promise<void> {
    const filePath = path.join(this.uploadDir, filename)
    try {
      await fs.unlink(filePath)
      this.logger.log(`Deleted file: ${filename}`)
    } catch (error) {
      this.logger.warn(`Failed to delete file: ${filename}`, error)
    }
  }

  async getFileInfo(filename: string): Promise<{ size: number; sha256: string } | null> {
    const filePath = path.join(this.uploadDir, filename)
    try {
      const buffer = await fs.readFile(filePath)
      const sha256 = crypto.createHash('sha256').update(buffer).digest('hex')
      return {
        size: buffer.length,
        sha256,
      }
    } catch {
      return null
    }
  }
}
