// @ts-nocheck

import { walkDir, removeIndex, isIndexEnd } from "./util"
import * as Joi from "joi"
const path = require("path")
const fs = require("fs")

class routePlugin {
    public name: string = "routePlugin"
    public version: string = "0.0.1"
    public register(server: any, opts: any) {
        const sourceDir = opts.sourceDir
        const type = opts.type || "jwt"
        const auth = opts.auth || []
        let array = []
        for (let i = 0; i < sourceDir.length; i++) {
            const dir = sourceDir[i]
            console.log(dir)
            array.push(dir.dir + "对应路径:")
            array = array.concat(this.registerRoute(server, dir.dir, dir.prefix || "", auth, type))
        }
        fs.writeFileSync(path.resolve(process.cwd(), "route.txt"), array.join("\n"), {
            encoding: "utf-8",
        })
    }
    registerRoute(server, sourceDir, prefix, auth, type) {
        const files = walkDir(sourceDir)
        const routes = []
        files.forEach(file => {
            let filename = file.relativeFileNoExt
            let array = filename.split(path.sep).slice(1)
            let fileNoExt = removeIndex("/" + array.join("/"))
            const moduleName = path.resolve(sourceDir, filename)
            const obj = require(moduleName)
            if (obj.default) {
                const func = new (obj.default || obj)()
                const prototype = Object.getPrototypeOf(func)
                const keys = Reflect.ownKeys(prototype)
                for (const key of keys) {
                    if (key !== "constructor") {
                        let ff = func[key]
                        let handler: () => void = undefined
                        // 默认方法
                        const method = ff.$method || "GET"
                        // 路由收集规则
                        let route = ""
                        if(ff.$route_path){
                            route = ff.$route_path
                            route = prefix ?  route[0] + prefix + "/" + route.slice(1) : route
                        }else{
                            if (ff.$route) {
                                if (isIndexEnd(fileNoExt)) {
                                    route = ff.$route
                                } else {
                                    route = fileNoExt + ff.$route
                                }
                            } else {
                                if (isIndexEnd(fileNoExt)) {
                                    route = fileNoExt + key.toString()
                                } else {
                                    route = fileNoExt + "/" + key.toString()
                                }
                            }
                            route = removeIndex(route)
                            route = prefix ? route[0] + prefix + "/" + route.slice(1) : route
                        }
                        // 配置规则
                        const options = ff.$options ? ff.$options : {}
                        if (!options.auth) {
                            if (ff.$auth == undefined) {
                                if (auth && auth.length && auth.filter(v => route.startsWith(v)).length) {
                                    options.auth = type
                                } else {
                                    // 默认是try
                                    options.auth = {
                                        strategy: type,
                                        mode: "try",
                                    }
                                }
                            } else if (ff.$auth) {
                                if(typeof ff.$auth === "boolean" && ff.$auth){
                                    options.auth = type
                                }else if(typeof ff.$auth === "boolean"){
                                    options.auth = false
                                }else {
                                    options.auth = {
                                        strategy: type,
                                        mode: ff.$auth,
                                    }
                                }
                            } else {
                                options.auth = false
                            }
                        }
                        if (!options.validate) {
                            let validateObj = ff.$validate || {}
                            if (options.auth && type === "jwt") {
                                if (validateObj.headers) {
                                    validateObj.headers = validateObj.headers.keys({
                                        Authorization: Joi.string(),
                                    })
                                } else {
                                    validateObj.headers = Joi.object({
                                        headers: Joi.object({
                                            Authorization: Joi.string(),
                                        }).unknown(), // 注意加上这个
                                    })
                                }
                            }
                            if (validateObj && !!Object.keys(validateObj).length) {
                                const failReason = validateObj.failReason
                                delete validateObj.failReason
                                if (validateObj.failAction === "log") {
                                    if (!options.log) options.log = {}
                                    options.log.collect = true
                                    let errto = validateObj.$errto
                                    handler = async function (...argus) {
                                        const request = argus[0]
                                        const h = argus[1]
                                        if (request.logs && !!request.logs.length && errto) {
                                            // request.yar.flash('error', request.logs.map((v: any)=>v.error.message));
                                            request.yar.flash("error", failReason || request.logs.map((v: any)=>v.error.message))
                                            return h.redirect(errto)
                                        }
                                        return await ff.call(this, ...argus)
                                    }
                                }
                                if (validateObj.failAction === "function") {
                                    let errto = validateObj.$errto
                                    validateObj.failAction = async function (request, h, err) {
                                        if (err.details) {
                                            request.$joi_error = err.details.map(v => v.message)
                                        }
                                        return h.continue
                                    }
                                    handler = async function (...argus) {
                                        const request = argus[0]
                                        const h = argus[1]
                                        if (request.$joi_error) {
                                            loggerSite.debug("传输参数错误: ", request.$joi_error)
                                            request.yar.flash("error", failReason || request.$joi_error)
                                            delete request.$joi_error
                                            return h.redirect(errto)
                                        }
                                        return await ff.call(this, ...argus)
                                    }
                                }
                                options.validate = validateObj
                            }
                        }
                        // && route.startsWith("/api")
                        if (ff.$swagger) {
                            options.description = ff.$swagger[0]
                            options.notes = ff.$swagger[1]
                            options.tags = ff.$swagger[2]
                        }
                        let str = route
                        if (
                            (typeof options.auth === "string" && options.auth) ||
                            (typeof options.auth === "object" && options.auth.mode === "required")
                        ) {
                            str = " 需要权限             : " + " " + full(method) + " " + str
                        } else if (typeof options.auth === "object" && options.auth.mode === "optional") {
                            str = " 不需权限(提供即需验证optional): " + " " + full(method) + " " + str
                        } else if (typeof options.auth === "object" && options.auth.mode === "try") {
                            str = " 不需权限(提供无需验证try): " + " " + full(method) + " " + str
                        } else {
                            str = " 不需权限             : " + " " + full(method) + " " + str
                        }
                        routes.push(str)

                        if (options.validate && options.validate.$errto) {
                            delete options.validate.$errto
                        }
                        if (!handler) {
                            handler = ff
                        }
                        if(Array.isArray(method)){
                            for (let i = 0; i < method.length; i++) {
                                const m = method[i];
                                const op = Object.assign({}, options)
                                if(m.toLowerCase() === "get"){
                                    // get请求没有这个
                                    delete op.payload
                                }
                                server.route({
                                    method: m,
                                    path: route,
                                    handler: handler,
                                    options: op,
                                })
                            }
                        }else{
                            server.route({
                                method: method,
                                path: route,
                                handler: handler,
                                options: options,
                            })
                        }
                    }
                }
            }
        })
        return routes
    }
}

function full(str: string, length = 10) {
    let len = str.length
    let need = length - len
    if (need <= 0) return str
    return str + [...Array(need)].map((v, i) => " ").join("")
}

const plugin = new routePlugin()

export { plugin }
export * from "./util/decorators"