import * as fs from 'node:fs/promises';
import * as path from 'node:path';
import { existsSync } from 'node:fs';
import * as crypto from 'node:crypto';

export class FileCacheAdapter {
    private cacheDir: string;
    private prefix: string;
    private defaultTTL: number;

    constructor(config?: { cacheDir?: string; prefix?: string; defaultTTL?: number }) {
        this.cacheDir = config?.cacheDir || path.resolve(process.cwd(), '.cache');
        this.prefix = config?.prefix || '';
        this.defaultTTL = config?.defaultTTL || 3600;

        if (!existsSync(this.cacheDir)) {
            fs.mkdir(this.cacheDir, { recursive: true }).catch(() => { });
        }
    }

    private sanitize(key: string): string {
        const clean = key.replace(/[^a-z0-9]/gi, '_');
        if (clean.length > 64) {
            return crypto.createHash('md5').update(key).digest('hex');
        }
        return clean;
    }

    private getFilePath(key: string): string {
        const safeKey = this.sanitize(`${this.prefix}${key}`).toLowerCase();
        return path.join(this.cacheDir, `${safeKey}.json`);
    }

    async get<T>(key: string): Promise<T | null> {
        const filePath = this.getFilePath(key);
        try {
            if (!existsSync(filePath)) return null;
            const content = await fs.readFile(filePath, 'utf8');
            const data = JSON.parse(content);

            if (data.expiry && Date.now() > data.expiry) {
                await this.del(key);
                return null;
            }

            return data.value;
        } catch (_error) {
            return null; // Keeping original return type Promise<T | null>
        }
    }

    async set<T>(key: string, value: T, ttl?: number): Promise<void> {
        const filePath = this.getFilePath(key);
        const effectiveTTL = ttl !== undefined ? ttl : this.defaultTTL;
        const data = {
            value,
            expiry: effectiveTTL > 0 ? Date.now() + effectiveTTL * 1000 : null,
            updatedAt: new Date().toISOString()
        };

        try {
            await fs.writeFile(filePath, JSON.stringify(data, null, 2), 'utf8');
        } catch (_error) {
            // Ignore
        }
    }

    async del(key: string): Promise<void> {
        const filePath = this.getFilePath(key);
        try {
            if (existsSync(filePath)) {
                await fs.unlink(filePath);
            }
        } catch (_error) {
            // Ignored - best effort cleanup
        }
    }
}
