import { SpruceSchemas } from '@sprucelabs/mercury-types'
import { Schema, SchemaValues } from '@sprucelabs/schema'
import { Templates } from '@sprucelabs/spruce-templates'
import { GlobalEmitter } from '../GlobalEmitter'
import ServiceFactory from '../services/ServiceFactory'
import StoreFactory from '../stores/StoreFactory'
import { ApiClientFactory } from '../types/apiClient.types'
import {
    GeneratedFile,
    NpmPackage,
    InternalUpdateHandler,
} from '../types/cli.types'
import { GraphicsInterface } from '../types/cli.types'
import WriterFactory from '../writers/WriterFactory'
import AbstractFeature from './AbstractFeature'
import ActionExecuter from './ActionExecuter'
import FeatureInstaller from './FeatureInstaller'

export interface FeatureMap {}
export interface FeatureOptionsMap {}

export type InstallFeature<
    Keys extends keyof FeatureOptionsMap = keyof FeatureOptionsMap,
> = {
    [Key in Keys]: Omit<
        {
            code: Key
            options: FeatureOptionsMap[Key]
        },
        FeatureOptionsMap[Key] extends Record<string, any> ? never : 'options'
    >
}[Keys]

export interface ActionOptions {
    templates: Templates
    serviceFactory: ServiceFactory
    cwd: string
    parent: AbstractFeature
    storeFactory: StoreFactory
    featureInstaller: FeatureInstaller
    ui: GraphicsInterface
    writerFactory: WriterFactory
    emitter: GlobalEmitter
    actionExecuter: ActionExecuter
    apiClientFactory: ApiClientFactory
}

export type FeatureCode = keyof FeatureMap

export type FeatureExecuteOptions<F extends FeatureCode> =
    FeatureMap[F]['optionsSchema'] extends Schema
        ? SchemaValues<FeatureMap[F]['optionsSchema']>
        : undefined

export interface InstallFeatureOptions {
    features: InstallFeature[]
    installFeatureDependencies?: boolean
    didUpdateHandler?: InternalUpdateHandler
}

export interface FeatureInstallResponse {
    files?: GeneratedFile[]
    packagesInstalled?: NpmPackage[]
}

export type FeatureActionResponse =
    SpruceSchemas.SpruceCli.v2020_07_22.ActionResponse & FeatureInstallResponse

export interface FeatureAction<S extends Schema = Schema> {
    optionsSchema?: S
    commandAliases: string[]
    invocationMessage: string
    execute: (options: SchemaValues<S>) => Promise<FeatureActionResponse>
}
