import type { ErrorOptions } from '@stacksjs/logging';

declare type ErrorMessage = string

export class ErrorHandler {
  static isTestEnvironment = false
  static shouldExitProcess = true

  static handle(err: Error | ErrorMessage | unknown, options?: ErrorOptions): Error {
    this.shouldExitProcess = options?.shouldExit !== false
    if (options?.silent !== true)
      this.writeErrorToConsole(err)

    let errorMessage: string

    if (options?.message) {
      errorMessage = options.message
    }
    else if (err instanceof Error) {
      errorMessage = err.message
    }
    else if (typeof err === 'string') {
      errorMessage = err
    }
    else {
      errorMessage = JSON.stringify(err)
    }

    const error = new Error(errorMessage)

    if (err instanceof Error) {
      Object.assign(error, err)
    }

    this.writeErrorToFile(error).catch(e => console.error(e))

    return error
  }

  static handleError(err: Error, options?: ErrorOptions): Error {
    this.handle(err, options)
    return err
  }

  static async writeErrorToFile(err: Error | unknown): Promise<void> {
    if (!(err instanceof Error)) {
      console.error('Error is not an instance of Error:', err)
      return
    }

    const formattedError = `[${new Date().toISOString()}] ${err.name}: ${err.message}\n`
    const logFilePath = path.logsPath('stacks.log') ?? path.logsPath('errors.log')

    try {
      await mkdir(path.dirname(logFilePath), { recursive: true })
      await appendFile(logFilePath, formattedError)
    }
    catch (error) {
      console.error('Failed to write to error file:', error)
    }
  }

  static writeErrorToConsole(err: string | Error | unknown): void {
    console.error(err)

    const errorString = typeof err === 'string' ? err : err instanceof Error ? err.message : JSON.stringify(err)

    if (
      errorString.includes('bunx --bun cdk destroy')
      || errorString === `Failed to execute command: ${italic('bunx --bun eslint . --fix')}`
      || errorString === `Failed to execute command: ${italic('bun storage/framework/core/actions/src/lint/fix.ts')}`
    ) {
      if (!this.isTestEnvironment) {
        console.log(
          'No need to worry. The edge function is currently being destroyed. Please run `buddy undeploy` shortly again, and continue doing so until it succeeds running.',
        )
        console.log('Hoping to see you back soon!')
      }
    }

    if (this.shouldExitProcess) {
      process.exit(ExitCode.FatalError)
    }
  }
}

interface WriteOptions {
  logFile?: string
}

let defaultLogPath = 'storage/logs/stacks.log'
export declare function setLogPath(path: string): void;
export declare function handleError(err: string | Error | object | unknown, options?: ErrorOptions | Record<string, any>): Error;