import { createHash } from 'crypto';
import { existsSync, mkdirSync, statSync, createReadStream, writeFileSync } from 'fs';
import { join } from 'path';
import type { Readable } from 'stream';

const MAX_AGE_MS = 24 * 60 * 60 * 1000; // 24 hours

export class ScreenshotCache {
  private dir: string;

  constructor(dir: string) {
    this.dir = dir;
    if (!existsSync(dir)) {
      mkdirSync(dir, { recursive: true });
    }
  }

  /**
   * Build a cache key by quantizing view params and hashing.
   * - lat/lng quantized to 2 decimal places
   * - zoom quantized to integer
   * - filters sorted alphabetically
   */
  buildKey(params: Record<string, string>): string {
    const normalized: Record<string, string> = {};

    // Parse and quantize the view param (lat,lng,zoom)
    if (params.v) {
      const parts = params.v.split(',');
      if (parts.length === 3) {
        const lat = parseFloat(parts[0]).toFixed(2);
        const lng = parseFloat(parts[1]).toFixed(2);
        const zoom = Math.round(parseFloat(parts[2])).toString();
        normalized.v = `${lat},${lng},${zoom}`;
      } else {
        normalized.v = params.v;
      }
    }

    // Sort filters
    if (params.f) {
      const segments = params.f.split(',').sort();
      normalized.f = segments.join(',');
    }

    if (params.poi) {
      const cats = params.poi.split(',').sort();
      normalized.poi = cats.join(',');
    }

    if (params.tab) {
      normalized.tab = params.tab;
    }

    const input = JSON.stringify(normalized);
    const hash = createHash('sha256').update(input).digest('hex').substring(0, 16);
    return hash;
  }

  getPath(key: string): string {
    return join(this.dir, `${key}.png`);
  }

  /**
   * Returns a readable stream if a fresh cached file exists, null otherwise.
   */
  get(key: string): Readable | null {
    const path = this.getPath(key);
    if (!existsSync(path)) return null;

    try {
      const stat = statSync(path);
      const age = Date.now() - stat.mtimeMs;
      if (age > MAX_AGE_MS) return null;
      return createReadStream(path);
    } catch {
      return null;
    }
  }

  /**
   * Write screenshot bytes to cache.
   */
  set(key: string, data: Buffer): void {
    const path = this.getPath(key);
    writeFileSync(path, data);
  }
}
