import fs from 'fs';
import { IApiDocFuncInterface, IParamsType } from "../base/interface";
import ApiGenerateImpl from "../interface/api_generate_impl";
import { execSync } from 'child_process';

export default class DocUtil {

    static runner(app: string) {
        execSync("cd ../" + app + " && flutter pub run build_runner build ");
    }


    static firstUpper(name: string) {
        let nameSpilit = name.split("");
        nameSpilit[0] = name[0].toUpperCase();
        return nameSpilit.join("");
    }

    static lowerCamelCase(name: string) {
        let nameSpilit = name.split("_");
        if (nameSpilit.length > 1) {
            nameSpilit.forEach((p, i) => {
                if (i > 0) {
                    nameSpilit[i] = this.firstUpper(nameSpilit[i]);
                }
            })
        }
        return nameSpilit.join("");
        // nameSpilit[0] = name[0].toUpperCase();
        // return nameSpilit.join("");
    }

    public info: ApiGenerateImpl;

    public entity: string = "";
    public funcs: string = "";




    constructor(_info: ApiGenerateImpl) {
        this.info = _info;
        let api = this.info.doc;
        for (const key in api) {
            const apis = api[key];
            for (const objKey in apis) {
                const element = (apis as any)[objKey] as IApiDocFuncInterface;
                if (['post', 'put', 'get', 'delete'].includes(objKey)) {
                    let name = `${apis.funcName}Using${DocUtil.firstUpper(objKey)}`;
                    let entityName = DocUtil.firstUpper(name);
                    let body = !!element.body && this.paramsTemple(`${entityName}Body`, element.body) && `${entityName}Body`;
                    let params = !!element.params && this.paramsTemple(`${entityName}Params`, element.params) && `${entityName}Params`;
                    let response: string | false = false;
                    let responseList = false;
                    /// 是否复杂的返回值-需要反序列化
                    let responsecomplex = false;
                    if (element.response) {
                        if (typeof element.response === "string") {
                            response = element.response;
                        }
                        else if (Array.isArray(element.response)) {
                            responseList = true;
                            // response = `List<${element.}>`;
                            let _type = element.response[0];
                            if (typeof _type === "string") {
                                response = _type;
                            }
                            else {
                                responsecomplex = true;
                                response = this.paramsTemple(`${entityName}Response`, _type) && `${entityName}Response`;
                            }
                        }
                        else {
                            responsecomplex = true;
                            response = this.paramsTemple(`${entityName}Response`, element.response) && `${entityName}Response`;
                        }
                    }
                    // let response = !!element.response && ((typeof element.response === "string") ? element.response : this.paramsTemple(`${entityName}Response`, element.response) && `${entityName}Response`);
                    this.funcs += this.funcTemple({
                        desc: apis.desc,
                        name,
                        method: objKey,
                        url: key,
                        body,
                        params,
                        response,
                        responseList,
                        responsecomplex,
                        element
                    });

                }
            }
        }
        fs.writeFileSync(this.info.filePath + "/" + this.info.fileName + ".dart", this.buildContent());
    }

    // enum StatusCode {
    //     @JsonValue(200)
    //     success,
    //     @JsonValue('500')
    //     weird,
    //   }

    public buildContent() {
        return `
        import 'package:dio/dio.dart';
        import 'package:dc/utils/request_util.dart';
        import 'package:json_annotation/json_annotation.dart';
        part '${this.info.fileName + ".g.dart"}';
        ${this.entity}
        
        class ${this.info.name} {
            ${this.funcs}
        }
        `
    };


    public funcTemple(obj: {
        name: string,
        desc?: string,
        method: string,
        url: string,
        body: string | false,
        params: string | false,
        response: string | false,
        responseList: boolean,
        responsecomplex: boolean,
        element: IApiDocFuncInterface
    }) {
        let serialize = "";
        let _response = obj.response || "dynamic";
        if (obj.response) {
            if (obj.responseList) {
                _response = `List<${obj.response}>`;
            }
            if (obj.responsecomplex) {
                if (obj.responseList) {
                    serialize = `, serialize: (data)=> [for (var i in data) ${obj.response}.fromJson(i)]`;
                } else {
                    serialize = `, serialize: (data)=> ${obj.response}.fromJson(data)`;
                }
            }
            else {
                serialize = `,serialize:(dynamic data)=>data`
            }
        }
        let url = obj.url;
        if (obj.element.params) {
            for (const key in obj.element.params) {
                const element = obj.element.params[key];
                if (element.url === true) {
                    url = url.replace(`{${key}}`, `\${params.${key}}`);
                }
            }
        }

        return (
            `   
        /// ${obj.desc}
        static RequestUtil<${_response || "dynamic"}> ${obj.name}({${obj.body ? "required" : ""} ${obj.body || "dynamic"} body,${obj.params ? "required" : ""} ${obj.params || "dynamic"} params, bool showLoading = false, bool tips = false, bool errorTips = false, bool successTips = false, Options? options, Function(int, int)? onSendProgress,}) {
            return RequestUtil<${_response || "dynamic"}>('${url}', RequestMethod.${obj.method}, body: body${obj.body ? ".toJson()" : ""}, params: params${obj.params ? ".toJson()" : ""}, showLoading: showLoading, tips: tips, errorTips: errorTips, successTips: successTips, options: options,onSendProgress:onSendProgress${serialize},);
        }
    `
        )
    };

    public enumTemple(name: string, params: Record<string, number | string>) {
        let _list: string[] = []
        for (const key in params) {
            const element = params[key];
            let _element = typeof element === "string" ? `"${element}"` : element;
            _list.push(`@JsonValue(${_element})`);
            _list.push(DocUtil.lowerCamelCase(element.toString()) + ",");
        }
        this.entity +=
            `
        enum ${DocUtil.firstUpper(name)} {
            ${_list.join("\r\n")}
          }
        `
    }

    public paramsTemple(name: string, params: Record<string, IParamsType>) {
        let str = "";
        let iniStr: string[] = [];

        for (const key in params) {
            const element = params[key];
            let jsonKey = element.jsonKey ? `@JsonKey(name: "${element.jsonKey}")` : "";
            let _final = element.final != false ? "final " : "";
            if (element.type === "object" && element.child && typeof element.child !== "string") {
                this.paramsTemple(name + DocUtil.firstUpper(key), element.child);
                str += `
                /// ${element.desc}
                ${jsonKey}
                ${_final} ${name + DocUtil.firstUpper(key)}${element.required != false ? "" : "?"} ${key};
                `
                iniStr.push(` ${element.required != false ? "required" : ""} this.${key}`);
            }
            else if (element.type === "enum") {
                if (element.enum) {
                    this.enumTemple(name + DocUtil.firstUpper(key), element.enum);
                    str += `
                    /// ${element.desc}
                    ${jsonKey}
                    ${_final} ${name + DocUtil.firstUpper(key)}${element.required != false ? "" : "?"} ${key};
                    `
                    iniStr.push(` ${element.required != false ? "required" : ""} this.${key}`);
                }
            }
            else if (element.type === "list" && element.child) {
                let _type = "";
                if (typeof element.child !== "string") {
                    this.paramsTemple(name + DocUtil.firstUpper(key), element.child);
                    _type = name + DocUtil.firstUpper(key);
                }
                else {
                    _type = element.child;
                }
                str += `
                /// ${element.desc}
                ${jsonKey}
                ${_final} List<${_type}>${element.required != false ? "" : "?"} ${key};
                `
                iniStr.push(` ${element.required != false ? "required" : ""} this.${key}`);
            }
            else {
                str += `
                /// ${element.desc}
                ${jsonKey}
                ${_final} ${element.type}${element.required != false ? "" : "?"} ${key};
                `
                iniStr.push(` ${element.required != false ? "required" : ""} this.${key}`);
            }
        }

        this.entity += `
        @JsonSerializable()
        class ${name} {
    
        ${str}
    
        ${name}({${iniStr.join(", ")}});
    
        factory ${name}.fromJson(Map<String, dynamic> json) => _$${name}FromJson(json);
    
        Map<String, dynamic> toJson() => _$${name}ToJson(this);
        }
    `
        return true;
    }
}