import { Injectable } from '@nestjs/common';
import { ConfigService } from '@nestjs/config';
import { PutObjectCommand, S3Client } from '@aws-sdk/client-s3';
import { getSignedUrl } from '@aws-sdk/s3-request-presigner';
import { randomUUID } from 'crypto';
import type { JwtUserPayload } from '../auth/jwt.types';
import { TripsService } from '../trips/trips.service';
import type { MeterKind } from './files.types';

@Injectable()
export class FilesService {
  private readonly s3: S3Client | null;

  constructor(
    private readonly cfg: ConfigService,
    private readonly trips: TripsService,
  ) {
    const region = this.cfg.get<string>('S3_REGION');
    const bucket = this.cfg.get<string>('S3_BUCKET');
    const accessKeyId = this.cfg.get<string>('S3_ACCESS_KEY_ID');
    const secretAccessKey = this.cfg.get<string>('S3_SECRET_ACCESS_KEY');
    const endpoint = this.cfg.get<string>('S3_ENDPOINT');
    if (region && bucket && accessKeyId && secretAccessKey) {
      this.s3 = new S3Client({
        region,
        endpoint: endpoint || undefined,
        forcePathStyle: !!endpoint,
        credentials: { accessKeyId, secretAccessKey },
      });
    } else {
      this.s3 = null;
    }
  }

  async presignedMeterUpload(
    actor: JwtUserPayload,
    tripId: string,
    kind: MeterKind,
    contentType: string,
    fileName: string,
  ) {
    await this.trips.assertCanRead(actor, tripId);
    const folder =
      kind === 'start' ? 'images/start_meter_images' : 'images/end_meter_images';
    const safeName = fileName.replace(/[^a-zA-Z0-9._-]/g, '_');
    const key = `${folder}/${tripId}/${randomUUID()}-${safeName}`;
    const bucket = this.cfg.get<string>('S3_BUCKET');
    if (!this.s3 || !bucket) {
      const publicBase = this.cfg.get<string>('S3_PUBLIC_BASE_URL') ?? '';
      return {
        devPlaceholder: true,
        storagePath: key,
        publicUrl: publicBase ? `${publicBase.replace(/\/$/, '')}/${key}` : null,
        message:
          'S3 not configured. Set S3_BUCKET, S3_REGION, S3_ACCESS_KEY_ID, S3_SECRET_ACCESS_KEY for presigned PUT.',
      };
    }
    const cmd = new PutObjectCommand({
      Bucket: bucket,
      Key: key,
      ContentType: contentType,
    });
    const uploadUrl = await getSignedUrl(this.s3, cmd, { expiresIn: 3600 });
    const publicBase = this.cfg.get<string>('S3_PUBLIC_BASE_URL') ?? '';
    const publicUrl = publicBase
      ? `${publicBase.replace(/\/$/, '')}/${key}`
      : undefined;
    return { uploadUrl, storagePath: key, publicUrl, expiresInSeconds: 3600 };
  }
}
