import {
  Controller,
  Get,
  Post,
  Put,
  Delete,
  Patch,
  Param,
  Query,
  Body,
  UploadedFile,
  UseGuards,
  UseInterceptors,
  NotFoundException,
  Logger,
} from '@nestjs/common';
import { FileInterceptor } from '@nestjs/platform-express';
import { ConfigService } from '@nestjs/config';
import { PlatformAdminGuard } from '../../../guards/platform-admin.guard';
import { PlatformSuperAdminGuard } from '../../../guards/platform-super-admin.guard';
import { diskStorage } from 'multer';
import * as fs from 'fs';
import * as path from 'path';
import { AppVersionRepository } from '../../../infrastructure/repositories/app-version.repository';
import { Platform } from '../../../domain/entities/app-version.entity';
import { CreateVersionDto } from '../../../application/dtos/create-version.dto';
import { UpdateVersionDto } from '../../../application/dtos/update-version.dto';

const UPLOAD_DIR = '/data/versions';

@Controller('api/v1/versions')
@UseGuards(PlatformAdminGuard)
export class VersionController {
  private readonly logger = new Logger(VersionController.name);
  private readonly downloadBaseUrl: string;

  constructor(
    private readonly versionRepo: AppVersionRepository,
    private readonly config: ConfigService,
  ) {
    this.downloadBaseUrl = this.config.get<string>(
      'DOWNLOAD_BASE_URL',
      'https://it0api.szaiai.com/downloads/versions',
    );
    // Ensure upload directories exist
    for (const p of [Platform.ANDROID, Platform.IOS]) {
      const dir = path.join(UPLOAD_DIR, p.toLowerCase());
      fs.mkdirSync(dir, { recursive: true });
    }
  }

  @Get()
  async list(
    @Query('platform') platform?: string,
    @Query('includeDisabled') includeDisabled?: string,
  ) {
    const filter: { platform?: Platform; includeDisabled?: boolean } = {};
    if (platform) {
      filter.platform = platform.toUpperCase() as Platform;
    }
    if (includeDisabled === 'true') {
      filter.includeDisabled = true;
    }
    return this.versionRepo.findAll(filter);
  }

  @Get(':id')
  async getById(@Param('id') id: string) {
    const version = await this.versionRepo.findById(id);
    if (!version) throw new NotFoundException('Version not found');
    return version;
  }

  @Post()
  async create(@Body() dto: CreateVersionDto) {
    return this.versionRepo.create({
      ...dto,
      releaseDate: dto.releaseDate ? new Date(dto.releaseDate) : undefined,
    });
  }

  @Put(':id')
  async update(@Param('id') id: string, @Body() dto: UpdateVersionDto) {
    const existing = await this.versionRepo.findById(id);
    if (!existing) throw new NotFoundException('Version not found');
    return this.versionRepo.update(id, {
      ...dto,
      releaseDate: dto.releaseDate ? new Date(dto.releaseDate) : undefined,
    });
  }

  @Delete(':id')
  @UseGuards(PlatformSuperAdminGuard)
  async delete(@Param('id') id: string) {
    const version = await this.versionRepo.findById(id);
    if (!version) throw new NotFoundException('Version not found');

    // Delete the associated file if it exists
    if (version.downloadUrl) {
      const platformDir = version.platform.toLowerCase();
      const filename = path.basename(new URL(version.downloadUrl).pathname);
      const filePath = path.join(UPLOAD_DIR, platformDir, filename);
      if (fs.existsSync(filePath)) {
        fs.unlinkSync(filePath);
        this.logger.log(`Deleted file: ${filePath}`);
      }
    }

    await this.versionRepo.delete(id);
    return { deleted: true };
  }

  @Patch(':id/toggle')
  async toggle(@Param('id') id: string, @Body('isEnabled') isEnabled: boolean) {
    const existing = await this.versionRepo.findById(id);
    if (!existing) throw new NotFoundException('Version not found');
    return this.versionRepo.update(id, { isEnabled });
  }

  @Post('upload')
  @UseInterceptors(
    FileInterceptor('file', {
      storage: diskStorage({
        destination: (req, _file, cb) => {
          const platform = (req.body.platform || 'ANDROID').toLowerCase();
          const dir = path.join(UPLOAD_DIR, platform);
          fs.mkdirSync(dir, { recursive: true });
          cb(null, dir);
        },
        filename: (_req, file, cb) => {
          // Preserve original filename with timestamp prefix to avoid collisions
          const timestamp = Date.now();
          const safeName = file.originalname.replace(/[^a-zA-Z0-9._-]/g, '_');
          cb(null, `${timestamp}_${safeName}`);
        },
      }),
      limits: { fileSize: 500 * 1024 * 1024 }, // 500 MB
    }),
  )
  async upload(
    @UploadedFile() file: Express.Multer.File,
    @Body('platform') platform: string,
    @Body('versionName') versionName: string,
    @Body('buildNumber') buildNumber: string,
    @Body('changelog') changelog?: string,
    @Body('isForceUpdate') isForceUpdate?: string,
    @Body('minOsVersion') minOsVersion?: string,
    @Body('releaseDate') releaseDate?: string,
  ) {
    const platformEnum = (platform || 'ANDROID').toUpperCase() as Platform;
    const platformDir = platformEnum.toLowerCase();
    const downloadUrl = `${this.downloadBaseUrl}/${platformDir}/${file.filename}`;

    return this.versionRepo.create({
      platform: platformEnum,
      versionName,
      buildNumber,
      changelog: changelog || undefined,
      downloadUrl,
      fileSize: file.size,
      isForceUpdate: isForceUpdate === 'true',
      isEnabled: true,
      minOsVersion: minOsVersion || undefined,
      releaseDate: releaseDate ? new Date(releaseDate) : undefined,
    });
  }

  @Post('parse')
  @UseInterceptors(
    FileInterceptor('file', {
      storage: diskStorage({
        destination: '/tmp',
        filename: (_req, file, cb) => {
          cb(null, `parse_${Date.now()}_${file.originalname}`);
        },
      }),
      limits: { fileSize: 500 * 1024 * 1024 },
    }),
  )
  async parsePackage(
    @UploadedFile() file: Express.Multer.File,
    @Body('platform') platform: string,
  ) {
    try {
      // Dynamic import for app-info-parser (CommonJS module)
      const AppInfoParser = (await import('app-info-parser')).default;
      const parser = new AppInfoParser(file.path);
      const info = await parser.parse();

      let result: { versionName?: string; versionCode?: string; minSdkVersion?: string } = {};

      if (platform?.toUpperCase() === 'IOS') {
        result = {
          versionName: info.CFBundleShortVersionString,
          versionCode: info.CFBundleVersion,
          minSdkVersion: info.MinimumOSVersion,
        };
      } else {
        result = {
          versionName: info.versionName,
          versionCode: String(info.versionCode),
          minSdkVersion: info.usesSdk?.minSdkVersion
            ? String(info.usesSdk.minSdkVersion)
            : undefined,
        };
      }

      return result;
    } catch (err) {
      this.logger.warn(`Failed to parse package: ${(err as Error).message}`);
      return { versionName: null, versionCode: null, minSdkVersion: null };
    } finally {
      // Clean up temp file
      if (fs.existsSync(file.path)) {
        fs.unlinkSync(file.path);
      }
    }
  }
}
