import { BadRequestException, Injectable } from '@nestjs/common';
import { ConfigService } from '@nestjs/config';
import { randomUUID } from 'crypto';
import { promises as fs } from 'fs';
import path from 'path';

type StoredFile = {
  key: string;
  url: string;
  provider: 'local';
  size: number;
  contentType: string;
  originalName: string;
};

@Injectable()
export class StorageService {
  constructor(private readonly configService: ConfigService) {}

  async savePublicFile(
    file: Express.Multer.File | undefined,
    folder: string,
  ): Promise<StoredFile> {
    if (!file) {
      throw new BadRequestException('Arquivo nao enviado.');
    }

    const safeFolder = this.sanitizeSegment(folder || 'misc');
    const originalName = file.originalname || 'arquivo';
    const extension = path.extname(originalName).toLowerCase();
    const baseName = path.basename(originalName, extension);
    const safeName = this.sanitizeSegment(baseName || 'arquivo');
    const finalName = `${Date.now()}-${randomUUID()}-${safeName}${extension}`;
    const relativeKey = path.posix.join(safeFolder, finalName);
    const absoluteDir = path.join(this.getUploadRoot(), safeFolder);
    const absolutePath = path.join(absoluteDir, finalName);

    await fs.mkdir(absoluteDir, { recursive: true });
    await fs.writeFile(absolutePath, file.buffer);

    return {
      key: relativeKey,
      url: `${this.getPublicBaseUrl()}/uploads/${relativeKey}`,
      provider: 'local',
      size: file.size,
      contentType: file.mimetype || 'application/octet-stream',
      originalName,
    };
  }

  getUploadRoot() {
    const configured = this.configService.get<string>('UPLOAD_DIR');
    if (configured) {
      return configured;
    }
    return path.join(process.cwd(), 'storage', 'uploads');
  }

  private getPublicBaseUrl() {
    return (
      this.configService.get<string>('APP_URL') ||
      `http://localhost:${this.configService.get<number>('API_PORT') ?? 3001}`
    ).replace(/\/+$/, '');
  }

  private sanitizeSegment(value: string) {
    return value
      .trim()
      .toLowerCase()
      .replace(/[^a-z0-9-_]+/g, '-')
      .replace(/^-+|-+$/g, '') || 'arquivo';
  }
}
