import fs from "fs"
import path from "path"
import { EventBus } from "../events/bus"
import { Logger } from "../logger"
import { ConfigFile, ConfigFileSchema, DEFAULT_CONFIG } from "./schema"

export class ConfigStore {
  private cache: ConfigFile = DEFAULT_CONFIG
  private loaded = false

  constructor(
    private readonly configPath: string,
    private readonly eventBus: EventBus | undefined,
    private readonly logger: Logger,
  ) {}

  load(): ConfigFile {
    if (this.loaded) {
      return this.cache
    }

    try {
      const resolved = this.resolvePath(this.configPath)
      if (fs.existsSync(resolved)) {
        const content = fs.readFileSync(resolved, "utf-8")
        const parsed = JSON.parse(content)
        this.cache = ConfigFileSchema.parse(parsed)
        this.logger.debug({ resolved }, "Loaded existing config file")
      } else {
        this.cache = DEFAULT_CONFIG
        this.logger.debug({ resolved }, "No config file found, using defaults")
      }
    } catch (error) {
      this.logger.warn({ err: error }, "Failed to load config, using defaults")
      this.cache = DEFAULT_CONFIG
    }

    this.loaded = true
    return this.cache
  }

  get(): ConfigFile {
    return this.load()
  }

  replace(config: ConfigFile) {
    const validated = ConfigFileSchema.parse(config)
    this.commit(validated)
  }

  private commit(next: ConfigFile) {
    this.cache = next
    this.loaded = true
    this.persist()
    const published = Boolean(this.eventBus)
    this.eventBus?.publish({ type: "config.appChanged", config: this.cache })
    this.logger.debug({ broadcast: published }, "Config SSE event emitted")
    this.logger.trace({ config: this.cache }, "Config payload")
  }

  private persist() {
    try {
      const resolved = this.resolvePath(this.configPath)
      fs.mkdirSync(path.dirname(resolved), { recursive: true })
      fs.writeFileSync(resolved, JSON.stringify(this.cache, null, 2), "utf-8")
      this.logger.debug({ resolved }, "Persisted config file")
    } catch (error) {
      this.logger.warn({ err: error }, "Failed to persist config")
    }
  }

  private resolvePath(filePath: string) {
    if (filePath.startsWith("~/")) {
      return path.join(process.env.HOME ?? "", filePath.slice(2))
    }
    return path.resolve(filePath)
  }
}
