import {
  Injectable,
  NotFoundException,
  PayloadTooLargeException,
  UnprocessableEntityException,
} from '@nestjs/common';
import { randomBytes } from 'crypto';
import { existsSync, mkdirSync, unlinkSync, renameSync } from 'fs';
import { join } from 'path';

const SCREENSHOTS_DIR = join(process.cwd(), '..', '..', 'data', 'screenshots');
const MAX_SIZE = 10 * 1024 * 1024; // 10MB
const ALLOWED_MIMETYPES: Record<string, string> = {
  'image/png': 'png',
  'image/jpeg': 'jpg',
  'image/gif': 'gif',
  'image/webp': 'webp',
};
const ALLOWED_EXTENSIONS = new Set(['png', 'jpg', 'jpeg', 'gif', 'webp']);
const BASE62 = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789';

@Injectable()
export class ScreenshotsService {
  constructor() {
    if (!existsSync(SCREENSHOTS_DIR)) {
      mkdirSync(SCREENSHOTS_DIR, { recursive: true });
    }
  }

  generateId(): string {
    const bytes = randomBytes(8);
    let id = '';
    for (let i = 0; i < 8; i++) {
      id += BASE62[bytes[i] % 62];
    }
    return id;
  }

  validateFile(file: Express.Multer.File): string {
    if (!file) {
      throw new UnprocessableEntityException('No image provided');
    }

    if (file.size > MAX_SIZE) {
      throw new PayloadTooLargeException(
        `File too large: ${(file.size / 1024 / 1024).toFixed(1)}MB, max 10MB`,
      );
    }

    const ext = ALLOWED_MIMETYPES[file.mimetype];
    if (!ext) {
      throw new UnprocessableEntityException(
        `Invalid format: ${file.mimetype}. Allowed: png, jpg, gif, webp`,
      );
    }

    return ext;
  }

  getFilePath(id: string, ext: string): string {
    return join(SCREENSHOTS_DIR, `${id}.${ext}`);
  }

  findFile(id: string): { path: string; ext: string } | null {
    for (const ext of ALLOWED_EXTENSIONS) {
      const path = this.getFilePath(id, ext);
      if (existsSync(path)) {
        return { path, ext };
      }
    }
    return null;
  }

  upload(file: Express.Multer.File): {
    id: string;
    url: string;
    delete_url: string;
    size: number;
    created_at: string;
  } {
    const ext = this.validateFile(file);
    const id = this.generateId();

    // File already saved by multer diskStorage, just rename
    const targetPath = this.getFilePath(id, ext);
    renameSync(file.path, targetPath);

    return {
      id,
      url: `https://platform.myfitcrm.ru/s/${id}.${ext}`,
      delete_url: `https://api.myfitcrm.ru/v1/screenshots/${id}`,
      size: file.size,
      created_at: new Date().toISOString(),
    };
  }

  delete(id: string): void {
    const found = this.findFile(id);
    if (!found) {
      throw new NotFoundException(`Screenshot ${id} not found`);
    }
    unlinkSync(found.path);
  }

  getInfo(): {
    server_name: string;
    max_upload_size: string;
    allowed_formats: string[];
    version: string;
  } {
    return {
      server_name: 'MyFitCRM Screenshots',
      max_upload_size: '10MB',
      allowed_formats: ['png', 'jpg', 'gif', 'webp'],
      version: '1.0.0',
    };
  }

  getStorageDir(): string {
    return SCREENSHOTS_DIR;
  }
}
