import fs from "fs"
import path from "path"
import chalk from "chalk"

const logLevels = {
  error: 0,
  warn: 1,
  info: 2,
  debug: 3,
} as const

const levelColors = {
  error: "red",
  warn: "yellow",
  info: "green",
  debug: "blue",
} as const

const levelEmojis = {
  error: "❌",
  warn: "⚠️",
  info: "✅",
  debug: "🐛",
} as const

type LogLevel = "error" | "warn" | "info" | "debug"

interface SimpleLoggerOptions {
  logLevel?: LogLevel
  logFile?: string
  logFormat?: string
  dateFormat?: string
  maxFileSize?: number
  maxFiles?: number
}

class SimpleLogger {
  logLevel: "error" | "warn" | "info" | "debug"
  logFile: string | null
  logFormat: string
  dateFormat: string
  maxFileSize: number
  maxFiles: number

  constructor(options: SimpleLoggerOptions = {}) {
    this.logLevel = options.logLevel || "info"
    this.logFile = options.logFile || null
    this.logFormat =
      options.logFormat || "[{level}] [{timestamp}] - {message} - {emoji}"
    this.dateFormat = options.dateFormat || "yyyy-mm-dd HH:MM:ss"
    this.maxFileSize = options.maxFileSize || 1024 * 1024 * 10 // 10MB
    this.maxFiles = options.maxFiles || 5
  }

  log(level: LogLevel, message: string) {
    if (logLevels[level] <= logLevels[this.logLevel]) {
      const timestamp = this.formatDate(new Date())
      const logMessage = this.formatMessage(timestamp, level, message)

      console.log(logMessage)

      if (this.logFile) {
        this.writeToFile(logMessage)
      }
    }
  }

  formatDate(date: Date) {
    const year = String(date.getFullYear())
    const month = String(date.getMonth() + 1).padStart(2, "0")
    const day = String(date.getDate()).padStart(2, "0")
    const hours = String(date.getHours()).padStart(2, "0")
    const minutes = String(date.getMinutes()).padStart(2, "0")
    const seconds = String(date.getSeconds()).padStart(2, "0")

    return this.dateFormat
      .replace("yyyy", year)
      .replace("mm", month)
      .replace("dd", day)
      .replace("HH", hours)
      .replace("MM", minutes)
      .replace("ss", seconds)
  }

  formatMessage(timestamp: string, level: LogLevel, message: string) {
    const levelColor = levelColors[level] || "white"
    const levelEmoji = levelEmojis[level] || ""

    const formattedMessage = this.logFormat
      .replace("{timestamp}", chalk.magenta(timestamp))
      .replace("{level}", chalk[levelColor](level.toUpperCase()))
      .replace("{message}", message)
      .replace("{emoji}", levelEmoji)

    return formattedMessage
  }

  writeToFile(logMessage: string) {
    if (!this.logFile) {
      return
    }

    const fileSize = fs.existsSync(this.logFile)
      ? fs.statSync(this.logFile).size
      : 0

    if (fileSize >= this.maxFileSize) {
      this.rotateLogFile()
    }

    fs.appendFileSync(this.logFile, logMessage + "\n")
  }
  rotateLogFile() {
    if (!this.logFile) {
      return
    }

    const extension = path.extname(this.logFile)
    const baseName = path.basename(this.logFile, extension)
    const dirName = path.dirname(this.logFile)

    // Correcting the deletion and rotation logic
    const oldestFile = path.join(
      dirName,
      `${baseName}.${this.maxFiles}${extension}`
    )
    if (fs.existsSync(oldestFile)) {
      fs.unlinkSync(oldestFile)
    }

    for (let i = this.maxFiles - 1; i > 0; i--) {
      const currentFile = path.join(dirName, `${baseName}.${i}${extension}`)
      const newFile = path.join(dirName, `${baseName}.${i + 1}${extension}`)
      if (fs.existsSync(currentFile)) {
        fs.renameSync(currentFile, newFile)
      }
    }

    const newFirstFile = path.join(dirName, `${baseName}.1${extension}`)
    if (fs.existsSync(this.logFile)) {
      fs.renameSync(this.logFile, newFirstFile)
    }
  }

  error(message: string) {
    this.log("error", message)
  }

  warn(message: string) {
    this.log("warn", message)
  }

  info(message: string) {
    this.log("info", message)
  }

  debug(message: string) {
    this.log("debug", message)
  }
}

// module export default
export default SimpleLogger
