import { Controller, Get, Query, Param, Res, NotFoundException, Post, Body, UnauthorizedException, InternalServerErrorException, Logger } from '@nestjs/common';
import { Response } from 'express';
import { InstallService } from './install.service';
import { BuildService } from '../builds/build.service';

@Controller('api/install')
export class InstallController {
  private readonly logger = new Logger(InstallController.name);

  constructor(
    private installService: InstallService,
    private buildService: BuildService,
  ) { }

  @Get('public-settings')
  async publicSettings(@Query('userId') userId?: string) {
    return this.installService.getPublicSettings(userId);
  }

  @Get('short/:code')
  async shortRedirect(@Param('code') code: string) {
    const buildId = await this.installService.getBuildIdByShortCode(code);
    if (!buildId) throw new NotFoundException('Link not found');
    return { buildId };
  }

  @Get('info')
  async info(@Query('build_id') buildId: string) {
    if (!buildId) {
      throw new NotFoundException('Missing build_id');
    }
    const info = await this.installService.getInstallInfo(buildId);
    if (!info) {
      this.logger.warn(`Install info returned null for build_id=${buildId}`);
      throw new NotFoundException('Build not found or no longer available');
    }
    return info;
  }

  @Post('verify-password')
  async verifyPassword(
    @Body('buildId') buildId: string,
    @Body('password') password: string,
  ) {
    if (!buildId || !password) {
      throw new UnauthorizedException('Missing buildId or password');
    }
    const valid = await this.buildService.verifyBuildPassword(buildId, password);
    if (!valid) {
      throw new UnauthorizedException('Incorrect password');
    }
    return { success: true };
  }

  @Get('download/:buildIdOrCode')
  async downloadApk(
    @Param('buildIdOrCode') buildIdOrCode: string,
    @Res() res: Response,
  ) {
    if (!buildIdOrCode) {
      throw new NotFoundException('Missing buildId or short code');
    }

    let buildId = buildIdOrCode;
    if (/^[A-Z0-9]{8}$/.test(buildIdOrCode)) {
      const id = await this.installService.getBuildIdByShortCode(buildIdOrCode);
      if (!id) {
        throw new NotFoundException('Short code not found');
      }
      buildId = id;
    }

    let result: Awaited<ReturnType<InstallService['getApkStream']>>;
    try {
      result = await this.installService.getApkStream(buildId);
    } catch (err) {
      this.logger.error(`APK download failed for build ${buildId}: ${err instanceof Error ? err.message : err}`);
      result = null;
    }

    if (!result) {
      // Ultimate fallback: redirect the browser directly to Google Drive.
      // The browser handles Google's redirects/cookies natively — this always
      // works for files with anyone:reader permission, regardless of token state.
      const publicUrl = await this.installService.getPublicDownloadUrl(buildId);
      if (publicUrl) {
        this.logger.log(`Redirecting build ${buildId} to Google Drive (streaming failed)`);
        return res.redirect(302, publicUrl);
      }
      this.logger.warn(`APK stream returned null and no public URL for build ${buildId} (param: ${buildIdOrCode})`);
      throw new NotFoundException('Build not found or no longer available');
    }
    res.setHeader('Content-Type', result.mimeType);
    res.setHeader('Content-Disposition', `attachment; filename="${result.fileName}"`);
    if (result.size) {
      res.setHeader('Content-Length', result.size);
    }
    result.stream.pipe(res);
  }

  @Get('ipa/:buildId')
  async downloadIpa(
    @Param('buildId') buildId: string,
    @Res() res: Response,
  ) {
    if (!buildId) {
      throw new NotFoundException('Missing buildId');
    }

    let result: Awaited<ReturnType<InstallService['getIpaStream']>>;
    try {
      result = await this.installService.getIpaStream(buildId);
    } catch (err) {
      this.logger.error(`IPA download failed for build ${buildId}: ${err instanceof Error ? err.message : err}`);
      result = null;
    }

    if (!result) {
      const publicUrl = await this.installService.getPublicDownloadUrl(buildId);
      if (publicUrl) {
        this.logger.log(`Redirecting IPA build ${buildId} to Google Drive (streaming failed)`);
        return res.redirect(302, publicUrl);
      }
      throw new NotFoundException('Build not found or no longer available');
    }
    res.setHeader('Content-Type', result.mimeType);
    res.setHeader('Content-Disposition', `attachment; filename="${result.fileName}"`);
    if (result.size) {
      res.setHeader('Content-Length', result.size);
    }
    result.stream.pipe(res);
  }

  @Get('redirect')
  async redirect(
    @Query('build_id') buildId: string,
    @Res() res: Response,
  ) {
    if (!buildId) {
      throw new NotFoundException('Missing build_id');
    }
    const result = await this.installService.getBuildForRedirect(buildId);
    if (!result) {
      throw new NotFoundException('Build not found or no longer available');
    }
    return res.redirect(302, result.url);
  }
}
