package handlers

import (
	"net/http"

	"easydo-echo_win7/middleware"
	"easydo-echo_win7/models"
	"easydo-echo_win7/services"
	"easydo-echo_win7/utils"

	"github.com/jmoiron/sqlx"
	"github.com/labstack/echo-contrib/session"
	"github.com/labstack/echo/v4"
)

func Add_product_bom_to_routes(e *echo.Echo) {
	group := e.Group("/productBom")
	group.Use(middleware.AuthMiddleware)
	group.POST("/getPage", productBomGetPage)
	group.POST("/getChildrenList", productBomGetChildrenList)
	group.POST("/save", productBomSave)
	group.POST("/update", productBomUpdate)
	group.POST("/remove", productBomRemove)

}

func productBomGetPage(c echo.Context) error {
	var paramMap map[string]interface{}
	if err := c.Bind(&paramMap); err != nil {
		return c.JSON(http.StatusInternalServerError, utils.ErrorResponse("参数解析失败", err.Error()))
	}
	result, err := services.JdbcClient.GetJdbcPage(paramMap, models.ProductBom{})
	if err != nil {
		utils.PrintSqlErr(err)
		return c.JSON(http.StatusInternalServerError, utils.ErrorResponse("系统错误", err.Error()))
	}
	list := utils.ConvertInterface[[]models.ProductBom](result.Records)
	if len(list) == 0 {
		list = []models.ProductBom{}
	}
	for i := range list {
		model := list[i]
		material := new(models.ProductMaterial)
		material.Code = model.MaterialCode
		err = services.JdbcClient.GetJdbcModel(material)
		if err != nil {
			utils.PrintSqlErr(err)
			return c.JSON(http.StatusInternalServerError, utils.ErrorResponse("系统错误", err.Error()))
		}

		model.Material = material

		bomParam := new(models.ProductBom)
		bomParam.ParentId = model.ID
		count, err := services.JdbcClient.GetJdbcCount(bomParam)
		if err != nil {
			utils.PrintSqlErr(err)
			return c.JSON(http.StatusInternalServerError, utils.ErrorResponse("系统错误", err.Error()))
		}

		if count > 0 {
			isHaveChildren := models.Common_Value_True_Value
			model.IsHaveChildren = &isHaveChildren
		} else {
			isHaveChildren := models.Common_Value_False_Value
			model.IsHaveChildren = &isHaveChildren
		}

		if utils.IsNotEmpty(model.RouteId) {
			route := new(models.ProcessRoute)
			route.ID = model.RouteId
			err = services.JdbcClient.GetJdbcModelById(route)
			if err != nil {
				utils.PrintSqlErr(err)
				return c.JSON(http.StatusInternalServerError, utils.ErrorResponse("系统错误", err.Error()))
			}
			model.RouteName = route.Name
		}
		

		list[i] = model
	}
	result.Records = list
	return c.JSON(http.StatusOK, result)

}

func productBomGetChildrenList(c echo.Context) error {
	var paramMap map[string]interface{}
	if err := c.Bind(&paramMap); err != nil {
		return c.JSON(http.StatusInternalServerError, utils.ErrorResponse("参数解析失败", err.Error()))
	}
	result, err := services.JdbcClient.GetJdbcList(paramMap, models.ProductBom{})
	if err != nil {
		utils.PrintSqlErr(err)
		return c.JSON(http.StatusInternalServerError, utils.ErrorResponse("系统错误", err.Error()))
	}
	list := utils.ConvertInterface[[]models.ProductBom](result)
	if len(list) == 0 {
		return c.JSON(http.StatusOK, []string{})
	}
	for i := range list {
		model := list[i]
		material := new(models.ProductMaterial)
		material.Code = model.MaterialCode
		err = services.JdbcClient.GetJdbcModel(material)
		if err != nil {
			utils.PrintSqlErr(err)
			return c.JSON(http.StatusInternalServerError, utils.ErrorResponse("系统错误", err.Error()))
		}

		model.Material = material

		bomParam := new(models.ProductBom)
		bomParam.ParentId = model.ID
		count, err := services.JdbcClient.GetJdbcCount(bomParam)
		if err != nil {
			utils.PrintSqlErr(err)
			return c.JSON(http.StatusInternalServerError, utils.ErrorResponse("系统错误", err.Error()))
		}

		if count > 0 {
			isHaveChildren := models.Common_Value_True_Value
			model.IsHaveChildren = &isHaveChildren
		} else {
			isHaveChildren := models.Common_Value_False_Value
			model.IsHaveChildren = &isHaveChildren
		}

		if utils.IsNotEmpty(model.RouteId) {
			route := new(models.ProcessRoute)
			route.ID = model.RouteId
			err = services.JdbcClient.GetJdbcModelById(route)
			if err != nil {
				utils.PrintSqlErr(err)
				return c.JSON(http.StatusInternalServerError, utils.ErrorResponse("系统错误", err.Error()))
			}
			model.RouteName = route.Name
		}

		list[i] = model
	}
	return c.JSON(http.StatusOK, list)
}

func productBomSave(c echo.Context) error {
	tx, _ := services.MYSQL_DB.Beginx()

	bom := new(models.ProductBom)
	if err := c.Bind(bom); err != nil {
		return c.JSON(http.StatusInternalServerError, utils.ErrorResponse("参数解析失败", err.Error()))
	}
	if *bom.ParentId == "0" {
		exist_bom := new(models.ProductBom)
		exist_bom.MaterialCode = bom.MaterialCode
		exist_bom.ParentId = bom.ParentId
		count, err := services.JdbcClient.GetJdbcCount(exist_bom, tx)
		if err != nil {
			utils.PrintSqlErr(err)
			tx.Rollback()
			return c.JSON(http.StatusInternalServerError, utils.ErrorResponse("系统错误", ""))
		}
		if count > 0 {
			return c.JSON(http.StatusInternalServerError, utils.ErrorResponse("该物料已经添加过BOM,请勿重复添加", ""))
		}
	}

	status := models.Status_Enable
	bom.Status = &status
	if bom.ID == nil {
		sess, _ := session.Get("auth_session", c)
		err_msg := productBom_generateCode(bom, tx)
		if err_msg != "" {
			tx.Rollback()
			return c.JSON(http.StatusBadRequest, utils.ErrorResponse(err_msg, ""))
		}
		user_id, ok := sess.Values["user_id"].(int64)
		if !ok {
			return c.JSON(http.StatusInternalServerError, utils.ErrorResponse("用户请先登录", ""))
		}
		bom.CreateId = &user_id
		err := services.JdbcClient.JdbcInsert(bom, tx)
		if err != nil {
			utils.PrintSqlErr(err)
			tx.Rollback()
			return c.JSON(http.StatusInternalServerError, utils.ErrorResponse("系统错误", ""))
		}
	} else {
		err := services.JdbcClient.JdbcUpdateById(bom, tx)
		if err != nil {
			utils.PrintSqlErr(err)
			tx.Rollback()
			return c.JSON(http.StatusInternalServerError, utils.ErrorResponse("系统错误", ""))
		}
	}

	if bom.ChildrenList == nil {
		tx.Commit()
		return c.JSON(http.StatusOK, bom)
	}
	detail_list := *bom.ChildrenList
	for _, detail := range detail_list {
		detail.ParentId = bom.ID
		detail.BomCode = bom.BomCode
		err := services.JdbcClient.JdbcInsert(&detail, tx)
		if err != nil {
			utils.PrintSqlErr(err)
			tx.Rollback()
			return c.JSON(http.StatusInternalServerError, utils.ErrorResponse("系统错误", ""))
		}
	}
	tx.Commit()
	return c.JSON(http.StatusOK, bom)

}

func productBomUpdate(c echo.Context) error {
	tx, _ := services.MYSQL_DB.Beginx()

	bom := new(models.ProductBom)
	if err := c.Bind(bom); err != nil {
		return c.JSON(http.StatusInternalServerError, utils.ErrorResponse("参数解析失败", err.Error()))
	}
	sess, _ := session.Get("auth_session", c)
	user_id, ok := sess.Values["user_id"].(int64)
	if !ok {
		return c.JSON(http.StatusInternalServerError, utils.ErrorResponse("用户请先登录", ""))
	}
	bom.UpdateId = &user_id
	err := services.JdbcClient.JdbcUpdateById(bom, tx)
	if err != nil {
		utils.PrintSqlErr(err)
		tx.Rollback()
		return c.JSON(http.StatusInternalServerError, utils.ErrorResponse("系统错误", ""))
	}

	bomParam := new(models.ProductBom)
	bomParam.ParentId = bom.ID
	result, err := services.JdbcClient.GetJdbcListByObject(bomParam)
	if err != nil {
		utils.PrintSqlErr(err)
		tx.Rollback()
		return c.JSON(http.StatusInternalServerError, utils.ErrorResponse("系统错误", err.Error()))
	}
	exist_list := utils.ConvertInterface[[]models.ProductBom](result)

	remove_id_list := utils.Map(exist_list, func(product_bom models.ProductBom) string {
		return *product_bom.ID
	})

	if bom.ChildrenList == nil {
		tx.Commit()
		return c.JSON(http.StatusOK, bom)
	}
	detail_list := *bom.ChildrenList
	insert_list := utils.Filter(detail_list, func(item models.ProductBom) bool {
		return item.ID == nil || len(*item.ID) == 0
	})
	update_list := utils.Filter(detail_list, func(item models.ProductBom) bool {
		return item.ID != nil && len(*item.ID) > 0
	})
	update_id_list := utils.Map(update_list, func(product_bom models.ProductBom) string {
		return *product_bom.ID
	})

	remove_id_list = utils.SliceSubtract(remove_id_list, update_id_list)

	for _, insert_model := range insert_list {
		insert_model.ParentId = bom.ID
		insert_model.BomCode = bom.BomCode
		err := services.JdbcClient.JdbcInsert(&insert_model, tx)
		if err != nil {
			utils.PrintSqlErr(err)
			tx.Rollback()
			return c.JSON(http.StatusInternalServerError, utils.ErrorResponse("系统错误", ""))
		}
	}

	for _, update_model := range update_list {
		err := services.JdbcClient.JdbcUpdateById(&update_model, tx)
		if err != nil {
			utils.PrintSqlErr(err)
			tx.Rollback()
			return c.JSON(http.StatusInternalServerError, utils.ErrorResponse("系统错误", ""))
		}
	}

	for _, remove_id := range remove_id_list {
		remove_bom := new(models.ProductBom)
		remove_bom.ID = &remove_id
		err := services.JdbcClient.JdbcRemoveById(remove_bom, tx)
		if err != nil {
			utils.PrintSqlErr(err)
			tx.Rollback()
			return c.JSON(http.StatusInternalServerError, utils.ErrorResponse("系统错误", ""))
		}
	}

	tx.Commit()
	return c.JSON(http.StatusOK, bom)
}

func productBomRemove(c echo.Context) error {
	bom := new(models.ProductBom)
	if err := c.Bind(bom); err != nil {
		return c.JSON(http.StatusInternalServerError, utils.ErrorResponse("参数解析失败", err.Error()))
	}

	err := services.JdbcClient.JdbcRemoveById(bom)
	if err != nil {
		utils.PrintSqlErr(err)
		return c.JSON(http.StatusInternalServerError, utils.ErrorResponse("系统错误", err.Error()))
	}
	return c.JSON(http.StatusOK, bom)
}

func productBom_generateCode(model *models.ProductBom, tx *sqlx.Tx) string {
	sync := new(models.Synchronized)
	sync.Sync.Lock()
	defer sync.Sync.Unlock()

	if model.BomCode != nil && len(*model.BomCode) > 0 {
		modelParam := new(models.ProductBom)
		modelParam.BomCode = model.BomCode
		modelParam.TenantId = model.TenantId
		count, err := services.JdbcClient.GetJdbcCount(modelParam, tx)
		if err != nil {
			utils.PrintSqlErr(err)
			return "SQL执行失败"
		}
		if count > 0 {
			return "编号已存在，请重新填写"
		}
	} else {
		for {
			code, err := services.GetFlowNo(models.Flow_No_Type_Product_Bom, *model.TenantId, tx)
			if err != nil {
				return "自动生成编码失败"
			}
			modelParam := new(models.ProductBom)
			modelParam.BomCode = &code
			modelParam.TenantId = model.TenantId
			count, err := services.JdbcClient.GetJdbcCount(modelParam, tx)
			if err != nil {
				utils.PrintSqlErr(err)
				return "SQL执行失败"
			}
			if count == 0 {
				model.BomCode = &code
				break
			}
		}

	}
	return ""
}
