import { Args, Command, Flags } from '@oclif/core'
import { start } from '@vtex/fsp-local'
import { type LoadedModule, loadModules } from '../modules.js'

type HookParams = {
  modules: LoadedModule[]
  account: string
}

export class Dev extends Command {
  static args = {
    account: Args.string({
      required: true,
      description:
        'Store name key to be considered. It must match the keys on faststore.json, otherwise the first one found will be used.',
    }),
  }
  static description =
    'Runs the development server for the local storefront environment.'
  static examples = ['<%= config.bin %> <%= command.id %>']

  static flags = {
    'proxy-port': Flags.integer({
      required: false,
      description: 'Port used for the proxy server',
      default: 3000,
    }),
  }

  async run(): Promise<void> {
    this.log('Running faststore dev  🚀')

    const {
      args: { account },
      flags: { 'proxy-port': proxyPort },
    } = await this.parse(Dev)

    const modules = await loadModules(account)

    try {
      await this.runPreTasks({ modules, account })
      await this.runMainTasks({ modules, account })
      await this.runPostTasks({ modules, account })

      await start(account, proxyPort)
    } catch (error) {
      /**
       *  TODO: How do we deal with errors?
       *  Should we log any specific feedback given the failed task?
       */
      this.logToStderr('Something went wrong.')
      console.log(error)
    }
  }

  private async runMainTasks({ modules, account }: HookParams): Promise<void> {
    try {
      await Promise.all(
        modules.map(({ loadedCli, path, port }) => {
          const { dev } = loadedCli.commands
          return dev.run([account, path, port?.toString() ?? ''])
        })
      )
    } catch (error) {
      // FIXME: Add error handling
      console.log(error)
    }
  }

  private async runPostTasks({ modules }: HookParams): Promise<void> {
    try {
      await Promise.all(
        modules.map(({ loadedCli }) => {
          const postDev = loadedCli.hooks?.postDev
          if (postDev) return postDev()

          return Promise.resolve()
        })
      )
    } catch (error) {
      // FIXME: Add error handling
      console.log(error)
    }
  }

  private async runPreTasks({ modules }: HookParams): Promise<void> {
    try {
      await Promise.all(
        modules.map(({ loadedCli }) => {
          const preDev = loadedCli.hooks?.preDev
          if (preDev) return preDev()

          return Promise.resolve()
        })
      )
    } catch (error) {
      // FIXME: Add error handling
      this.logToStderr('Something went wrong.')
      console.log(error)
    }
  }
}
