import * as Pont from 'pont-engine'
import { Interface, BaseClass, Property, CodeGenerator } from 'pont-engine'

// 接口 API 前缀
// 通常与项目的 env 配置中的 VITE_GLOB_API_URL_PREFIX 相同
const API_URL_PREFIX = '/api'

export class FileStructures extends Pont.FileStructures {
    getModsDeclaration(originCode: string): string {
        return originCode
    }
}

export default class BasicGenerator extends CodeGenerator {
    checkJsonParam(inter: Interface, paramsCode: string): boolean {
        const prettier = require('prettier')
        const requestParams = inter.getRequestParams(this.surrounding)
        const code = prettier.format(paramsCode, { parser: 'typescript' })
        return code.includes('{}') && requestParams.includes('body')
    }

    // 认为没有返回值的接口表示下载（通常是）
    isDownload(inter: Interface): boolean {
        return inter.responseType === 'any'
    }

    // 认为包含 form 参数的接口表示带有上传功能
    isUpload(inter: Interface): boolean {
        return inter.getRequestParams(this.surrounding).includes('form')
    }

    getParams(inter: Interface, paramsCode: string) {
        let requestParams = inter.getRequestParams(this.surrounding)
        let bodyTypeDef = ''

        const prettier = require('prettier')
        if (prettier.format(paramsCode, { parser: 'typescript' }).includes('{}')) {
            if (!requestParams.includes('form')) {
                requestParams = requestParams.replace('params', 'params?')
            }

            if (requestParams.includes('body')) {
                requestParams = requestParams.replace('params?: Params, ', '')
                bodyTypeDef = requestParams.replace(/^.*body: (.*),.*$/gi, '$1')
            }
        }

        return `${requestParams.replace(
            'options?: any',
            `config?: http.RequestConfig<${
                bodyTypeDef ? bodyTypeDef : `Params${requestParams.includes('form') ? ' | FormData' : ''}`
            }>`,
        )}, options?: http.RequestOptions`
    }

    getInterfaceContentInDeclaration(inter: Interface) {
        const paramsCode = inter.getParamsCode('Params')
        const requestParams = this.getParams(inter, paramsCode)

        return `
            export ${paramsCode}

            export type Response = ${inter.responseType.replace(/defs.Result\<(.*)\>/, '$1')};

            export const init: Response;

            export function request(${requestParams}): Promise<Response>;
        `
    }

    getBaseClassInDeclaration(base: BaseClass) {
        const originProps = base.properties

        base.properties = base.properties.map((prop) => {
            return new Property({
                ...prop,
                required: false,
            })
        })

        const result = super.getBaseClassInDeclaration(base)
        base.properties = originProps

        return result
    }

    getInterfaceContent(inter: Interface) {
        const method = inter.method.toUpperCase()
        const paramsCode = inter.getParamsCode('Params', this.surrounding)
        const requestParams = this.getParams(inter, paramsCode)
        const undef = inter.response.getInitialValue() === 'undefined'
        const isBody = this.checkJsonParam(inter, paramsCode)

        // TODO
        // 扩展 hooks mode
        // 采用 vue-request 或 @tanstack/vue-query
        // export function useRequest()
        return `
            /**
             * @desc ${inter.description}
             */

            ${undef ? '' : `import * as defs from '../../baseClass';`}
            import { defHttp } from '/@/utils/http/axios'

            ${isBody ? '' : `export ${paramsCode}`}

            ${undef ? '' : `export const init = ${inter.response.getInitialValue(true)};`}

            export function request(${requestParams}) {
                return defHttp.request({
                    url: "${inter.path.replace(API_URL_PREFIX, '')}",
                    method: '${method}',
                    ${
                        method === 'GET'
                            ? 'params'
                            : `data: ${requestParams.includes('form') ? 'form || params' : isBody ? 'body' : 'params'}`
                    },
                    ${
                        requestParams.includes('form')
                            ? `headers: { 'Content-Type': 'multipart/form-data;charset=UTF-8' },`
                            : isBody
                            ? `headers: { 'Content-Type': 'application/json' },`
                            : ''
                    }

                    ...config,
                }, options);
            }
        `
    }

    reviseModName(modName: string) {
        // .replace(/\//g, '.').replace(/^\./, '').replace(/\./g, '_') 转换 / .为下划线
        // exp: /api/v1/users  => api_v1_users
        // exp: api.v1.users => api_v1_users
        return modName.replace(/\//g, '.').replace(/^\./, '').replace(/\./g, '_')
    }

    /** 获取所有模块的 index 入口文件 */
    getModsIndex() {
        let conclusion = `
            export const API = {
                ${this.dataSource.mods.map((mod) => this.reviseModName(mod.name)).join(', \n')}
            };
        `

        // dataSource name means multiple dataSource
        if (this.dataSource.name) {
            conclusion = `
                export const ${this.dataSource.name} = {
                    ${this.dataSource.mods.map((mod) => this.reviseModName(mod.name)).join(', \n')}
                };
            `
        }

        return `
            ${this.dataSource.mods
                .map((mod) => {
                    const modName = this.reviseModName(mod.name)
                    return `import * as ${modName} from './${modName}';`
                })
                .join('\n')}

            ${conclusion}
        `
    }

    /** 获取接口类和基类的总的 index 入口文件代码 */
    getIndex() {
        let conclusion = `
            import * as defs from './baseClass';
            import './mods/';

            export { defs };
        `

        // dataSource name means multiple dataSource
        if (this.dataSource.name) {
            conclusion = `
                import { ${this.dataSource.name} as defs } from './baseClass';
                export { ${this.dataSource.name} } from './mods/';
                export { defs };
            `
        }

        return conclusion
    }
}
