import * as fs from "fs";
import * as path from "path";

/**
 * Discovery Logger - Creates detailed log files for each discovery playlist generation
 */
class DiscoveryLogger {
    private logDir: string;
    private currentLogFile: string | null = null;
    private currentStream: fs.WriteStream | null = null;

    constructor() {
        // Store logs in /app/logs/discovery (matches Dockerfile directory)
        this.logDir = process.env.NODE_ENV === "production"
            ? "/app/logs/discovery"
            : path.join(process.cwd(), "data", "logs", "discovery");
    }

    /**
     * Start a new log file for a discovery generation
     */
    start(userId: string, jobId?: number): string {
        // Ensure log directory exists
        if (!fs.existsSync(this.logDir)) {
            fs.mkdirSync(this.logDir, { recursive: true });
        }

        // Create filename with timestamp
        const timestamp = new Date().toISOString().replace(/[:.]/g, "-");
        const filename = `discovery-${timestamp}-job${jobId || "manual"}.log`;
        this.currentLogFile = path.join(this.logDir, filename);

        // Open write stream
        this.currentStream = fs.createWriteStream(this.currentLogFile, { flags: "a" });

        // Write header
        this.write("═".repeat(60));
        this.write(`DISCOVERY WEEKLY GENERATION LOG`);
        this.write(`Started: ${new Date().toISOString()}`);
        this.write(`User ID: ${userId}`);
        this.write(`Job ID: ${jobId || "manual"}`);
        this.write("═".repeat(60));
        this.write("");

        return this.currentLogFile;
    }

    /**
     * Write a line to the current log
     */
    write(message: string, indent: number = 0): void {
        const prefix = "  ".repeat(indent);
        const timestamp = new Date().toISOString().split("T")[1].split(".")[0];
        const line = `[${timestamp}] ${prefix}${message}`;
        
        // Write to file
        if (this.currentStream) {
            this.currentStream.write(line + "\n");
        }
        
        // Also write to console for real-time visibility
        console.log(message);
    }

    /**
     * Write a section header
     */
    section(title: string): void {
        this.write("");
        this.write("─".repeat(50));
        this.write(`> ${title}`);
        this.write("─".repeat(50));
    }

    /**
     * Write a success message
     */
    success(message: string, indent: number = 0): void {
        this.write(`✓ ${message}`, indent);
    }

    /**
     * Write an error message
     */
    error(message: string, indent: number = 0): void {
        this.write(`✗ ${message}`, indent);
    }

    /**
     * Write a warning message
     */
    warn(message: string, indent: number = 0): void {
        this.write(`[WARN] ${message}`, indent);
    }

    /**
     * Write info message
     */
    info(message: string, indent: number = 0): void {
        this.write(`ℹ ${message}`, indent);
    }

    /**
     * Write a table of key-value pairs
     */
    table(data: Record<string, any>, indent: number = 1): void {
        for (const [key, value] of Object.entries(data)) {
            this.write(`${key}: ${value}`, indent);
        }
    }

    /**
     * Write a list of items
     */
    list(items: string[], indent: number = 1): void {
        for (const item of items) {
            this.write(`• ${item}`, indent);
        }
    }

    /**
     * End the current log and close the stream
     */
    end(success: boolean, summary?: string): void {
        this.write("");
        this.write("═".repeat(60));
        this.write(`GENERATION ${success ? "COMPLETED" : "FAILED"}`);
        if (summary) {
            this.write(summary);
        }
        this.write(`Ended: ${new Date().toISOString()}`);
        this.write("═".repeat(60));

        if (this.currentStream) {
            this.currentStream.end();
            this.currentStream = null;
        }
    }

    /**
     * Get the path to the current log file
     */
    getCurrentLogPath(): string | null {
        return this.currentLogFile;
    }

    /**
     * Get the most recent log file
     */
    getLatestLog(): { path: string; content: string } | null {
        if (!fs.existsSync(this.logDir)) {
            return null;
        }

        const files = fs.readdirSync(this.logDir)
            .filter(f => f.startsWith("discovery-") && f.endsWith(".log"))
            .sort()
            .reverse();

        if (files.length === 0) {
            return null;
        }

        const latestPath = path.join(this.logDir, files[0]);
        const content = fs.readFileSync(latestPath, "utf-8");
        
        return { path: latestPath, content };
    }

    /**
     * Get all log files (most recent first)
     */
    getAllLogs(): { filename: string; date: Date; size: number }[] {
        if (!fs.existsSync(this.logDir)) {
            return [];
        }

        return fs.readdirSync(this.logDir)
            .filter(f => f.startsWith("discovery-") && f.endsWith(".log"))
            .map(filename => {
                const filePath = path.join(this.logDir, filename);
                const stats = fs.statSync(filePath);
                return {
                    filename,
                    date: stats.mtime,
                    size: stats.size
                };
            })
            .sort((a, b) => b.date.getTime() - a.date.getTime());
    }

    /**
     * Get a specific log file content
     */
    getLogContent(filename: string): string | null {
        const filePath = path.join(this.logDir, filename);
        if (!fs.existsSync(filePath)) {
            return null;
        }
        return fs.readFileSync(filePath, "utf-8");
    }

    /**
     * Clean up old logs (keep last N)
     */
    cleanup(keepCount: number = 20): number {
        const logs = this.getAllLogs();
        let deleted = 0;

        for (let i = keepCount; i < logs.length; i++) {
            const filePath = path.join(this.logDir, logs[i].filename);
            fs.unlinkSync(filePath);
            deleted++;
        }

        return deleted;
    }
}

export const discoveryLogger = new DiscoveryLogger();






