package model

import (
	"errors"
	"github.com/fonchain_enterprise/fonchain-approval/api/approval"
	m2 "github.com/fonchain_enterprise/fonchain-approval/pkg/m"
	"github.com/jinzhu/copier"
	"gorm.io/plugin/soft_delete"
	"strconv"
	"time"
)

type ApprovalOA struct {
	ID         uint64                `gorm:"primaryKey;column:id" json:"id"`       // ID
	DeletedAt  soft_delete.DeletedAt `gorm:"column:deleted_at" json:"deletedAt"`   // 删除时间
	CreatedAt  time.Time             `gorm:"column:created_at" json:"createdAt"`   // 创建时间
	UpdatedAt  time.Time             `gorm:"column:updated_at" json:"updatedAt"`   // 更新时间
	ApprovalID uint64                `gorm:"column:approval_id" json:"approvalID"` // 申请的id
	LeaveApply *LeaveApply           `json:"leaveApply" gorm:"column:leave_apply;type:json;comment:假期余额申请"`
	OutWork    *OutWorkApply         `json:"outWork" gorm:"column:out_work;type:json;comment:外勤"`
	MakeUp     *MakeUpApply          `json:"makeUp" gorm:"column:make_up;type:json;comment:加班"`
	Turnover   *TurnoverApply        `json:"turnover" gorm:"column:turnover;type:json;comment:离职"`
	OverTime   *OverTimeApply        `json:"overTime" gorm:"column:over_time;type:json;comment:加班"`
	Leave      *Leave                `json:"leave" gorm:"column:leave;type:json;comment:请假"`
}

// LeaveApply
// 假期额度申请
type LeaveApply struct {
	UUID          string        `json:"UUID" gorm:"column:uuid,type:varchar(255),primaryKey"`
	StaffUID      string        `json:"staffUID" gorm:"column:staff_uid;type:varchar(255);comment:员工UID"`   // 员工UID
	StaffNum      string        `json:"staffNum" gorm:"column:staff_num;type:varchar(255);comment:员工编号"`    // 员工编号
	StaffName     string        `json:"staffName" gorm:"column:staff_name;type:varchar(255);comment:员工姓名"`  // 员工姓名
	DepartmentUID string        `json:"departmentUID" gorm:"column:department_uid;type:text;comment:部门UID"` // 部门UID
	ApplyType     string        `json:"applyType" gorm:"column:apply_type;type:varchar(255);comment:审批|请假类型"`
	ActionTime    string        `json:"actionTime" gorm:"column:action_time;type:varchar(255);comment:操作|申请时间"`
	ApprovalID    string        `json:"approvalID" gorm:"column:approval_id;type:varchar(255);comment:审批系统中的approvalID"`
	Reason        string        `json:"reason" gorm:"column:reason;type:varchar(255);comment:理由"`
	Status        int32         `json:"status" gorm:"column:status;type:int;comment:状态(目前和审批系统状态同步)"`
	VerifyFile    VerifyFiles   `json:"verifyFile" gorm:"column:verify_file;type:json;comment:证明文件(图片|pdf)"`
	ApprovalUsers ApprovalUsers `json:"approvalUsers" gorm:"column:approval_users;type:json;comment:审批人"`
	CopyUsers     CopyUsers     `json:"copyUsers" gorm:"column:copy_users;type:json;comment:抄送人"`
}

// OutWorkApply
// 外勤申请
type OutWorkApply struct {
	UUID           string        `json:"UUID" gorm:"column:uuid,type:varchar(255),primaryKey"`
	StaffUID       string        `json:"staffUID" gorm:"column:staff_uid;type:varchar(255);comment:员工UID"`   // 员工UID
	StaffNum       string        `json:"staffNum" gorm:"column:staff_num;type:varchar(255);comment:员工编号"`    // 员工编号
	StaffName      string        `json:"staffName" gorm:"column:staff_name;type:varchar(255);comment:员工姓名"`  // 员工姓名
	DepartmentUID  string        `json:"departmentUID" gorm:"column:department_uid;type:text;comment:部门UID"` // 部门UID
	ApplyType      string        `json:"applyType" gorm:"column:apply_type;type:varchar(255);comment:审批|请假类型"`
	ActionTime     string        `json:"actionTime" gorm:"column:action_time;type:varchar(255);comment:操作|申请时间"`
	ApplyTimes     ApplyTimes    `json:"applyTimes" gorm:"column:apply_times;type:json;comment:时间"`
	Hours          float32       `json:"hours" gorm:"column:hours;type:decimal(10,2);comment:时长(小时)"`
	OutWorkAddress string        `json:"outWorkAddress" gorm:"column:out_work_address;type:varchar(255);comment:外勤地址"`
	Vehicle        string        `json:"vehicle" gorm:"column:vehicle;type:varchar(255);comment:交通工具"`
	Reason         string        `json:"reason" gorm:"column:reason;type:varchar(255);comment:理由"`
	ApprovalID     string        `json:"approvalID" gorm:"column:approval_id;type:varchar(255);comment:审批系统中的approvalID"`
	Status         int32         `json:"status" gorm:"column:status;type:int;comment:状态(目前和审批系统状态同步)"`
	ApprovalUsers  ApprovalUsers `json:"approvalUsers" gorm:"column:approval_users;type:json;comment:审批人"`
	CopyUsers      CopyUsers     `json:"copyUsers" gorm:"column:copy_users;type:json;comment:抄送人"`
}

// MakeUpApply
// 补卡申请
type MakeUpApply struct {
	UUID          string        `json:"UUID" gorm:"column:uuid,type:varchar(255),primaryKey"`
	StaffUID      string        `json:"staffUID" gorm:"column:staff_uid;type:varchar(255);comment:员工UID"`   // 员工UID
	StaffNum      string        `json:"staffNum" gorm:"column:staff_num;type:varchar(255);comment:员工编号"`    // 员工编号
	StaffName     string        `json:"staffName" gorm:"column:staff_name;type:varchar(255);comment:员工姓名"`  // 员工姓名
	DepartmentUID string        `json:"departmentUID" gorm:"column:department_uid;type:text;comment:部门UID"` // 部门UID
	ApplyType     string        `json:"applyType" gorm:"column:apply_type;type:varchar(255);comment:审批|请假类型"`
	ActionTime    string        `json:"actionTime" gorm:"column:action_time;type:varchar(255);comment:操作|申请时间"`
	ApplyTimes    ApplyTimes    `json:"applyTimes" gorm:"column:apply_times;type:json;comment:时间"`
	Reason        string        `json:"reason" gorm:"column:reason;type:varchar(255);comment:理由"`
	ApprovalID    string        `json:"approvalID" gorm:"column:approval_id;type:varchar(255);comment:审批系统中的approvalID"`
	Status        int32         `json:"status" gorm:"column:status;type:int;comment:状态(目前和审批系统状态同步)"`
	ApprovalUsers ApprovalUsers `json:"approvalUsers" gorm:"column:approval_users;type:json;comment:审批人"`
	CopyUsers     CopyUsers     `json:"copyUsers" gorm:"column:copy_users;type:json;comment:抄送人"`
}

// TurnoverApply
// 离职申请
type TurnoverApply struct {
	UUID          string        `json:"UUID" gorm:"column:uuid,type:varchar(255),primaryKey"`
	StaffUID      string        `json:"staffUID" gorm:"column:staff_uid;type:varchar(255);comment:员工UID"`   // 员工UID
	StaffNum      string        `json:"staffNum" gorm:"column:staff_num;type:varchar(255);comment:员工编号"`    // 员工编号
	StaffName     string        `json:"staffName" gorm:"column:staff_name;type:varchar(255);comment:员工姓名"`  // 员工姓名
	DepartmentUID string        `json:"departmentUID" gorm:"column:department_uid;type:text;comment:部门UID"` // 部门UID
	ApplyType     string        `json:"applyType" gorm:"column:apply_type;type:varchar(255);comment:审批|请假类型"`
	ActionTime    string        `json:"actionTime" gorm:"column:action_time;type:varchar(255);comment:操作|申请时间"`
	Reason        string        `json:"reason" gorm:"column:reason;type:varchar(255);comment:理由"`
	HandoverUID   string        `json:"handoverUID" gorm:"column:handover_uid;type:varchar(255);comment:交接人"`
	HandoverName  string        `json:"handoverName" gorm:"column:handover_name;type:varchar(255);comment:交接人姓名"`
	ApplyTimes    ApplyTimes    `json:"applyTimes" gorm:"column:apply_times;type:json;comment:时间"`
	ApprovalID    string        `json:"approvalID" gorm:"column:approval_id;type:varchar(255);comment:审批系统中的approvalID"`
	Status        int32         `json:"status" gorm:"column:status;type:int;comment:状态(目前和审批系统状态同步)"`
	ApprovalUsers ApprovalUsers `json:"approvalUsers" gorm:"column:approval_users;type:json;comment:审批人"`
	CopyUsers     CopyUsers     `json:"copyUsers" gorm:"column:copy_users;type:json;comment:抄送人"`
}

// OverTimeApply
// 加班申请
type OverTimeApply struct {
	UUID          string        `json:"UUID" gorm:"column:uuid,type:varchar(255),primaryKey"`
	StaffUID      string        `json:"staffUID" gorm:"column:staff_uid;type:varchar(255);comment:员工UID"`   // 员工UID
	StaffNum      string        `json:"staffNum" gorm:"column:staff_num;type:varchar(255);comment:员工编号"`    // 员工编号
	StaffName     string        `json:"staffName" gorm:"column:staff_name;type:varchar(255);comment:员工姓名"`  // 员工姓名
	DepartmentUID string        `json:"departmentUID" gorm:"column:department_uid;type:text;comment:部门UID"` // 部门UID
	ApplyType     string        `json:"applyType" gorm:"column:apply_type;type:varchar(255);comment:审批|请假类型"`
	ApprovalID    string        `json:"approvalID" gorm:"column:approval_id;type:varchar(255);comment:审批系统中的approvalID"`
	ActionTime    string        `json:"actionTime" gorm:"column:action_time;type:varchar(255);comment:操作|申请时间"`
	ApplyTimes    ApplyTimes    `json:"applyTimes" gorm:"column:apply_times;type:json;comment:时间"`
	Reason        string        `json:"reason" gorm:"column:reason;type:varchar(255);comment:理由"`
	Hours         float32       `json:"hours" gorm:"column:hours;type:decimal(10,2);comment:时长(小时)"`
	Status        int32         `json:"status" gorm:"column:status;type:int;comment:状态(目前和审批系统状态同步)"`
	ApprovalUsers ApprovalUsers `json:"approvalUsers" gorm:"column:approval_users;type:json;comment:审批人"`
	CopyUsers     CopyUsers     `json:"copyUsers" gorm:"column:copy_users;type:json;comment:抄送人"`
}

// Leave
// 请假
type Leave struct {
	UUID          string        `json:"UUID" gorm:"column:uuid,type:varchar(255),primaryKey"`
	StaffUID      string        `json:"staffUID" gorm:"column:staff_uid;type:varchar(255);comment:员工UID"`   // 员工UID
	StaffNum      string        `json:"staffNum" gorm:"column:staff_num;type:varchar(255);comment:员工编号"`    // 员工编号
	StaffName     string        `json:"staffName" gorm:"column:staff_name;type:varchar(255);comment:员工姓名"`  // 员工姓名
	DepartmentUID string        `json:"departmentUID" gorm:"column:department_uid;type:text;comment:部门UID"` // 部门UID
	ApplyType     string        `json:"applyType" gorm:"column:apply_type;type:varchar(255);comment:审批|请假类型"`
	ActionTime    string        `json:"actionTime" gorm:"column:action_time;type:varchar(255);comment:操作|申请时间"`
	ApprovalID    string        `json:"approvalID" gorm:"column:approval_id;type:varchar(255);comment:审批系统中的approvalID"`
	ApplyTimes    ApplyTimes    `json:"applyTimes" gorm:"column:apply_times;type:json;comment:时间"`
	Reason        string        `json:"reason" gorm:"column:reason;type:varchar(255);comment:理由"`
	Hours         float32       `json:"hours" gorm:"column:hours;type:decimal(10,2);comment:时长(小时)"`
	Days          float32       `json:"days" gorm:"column:days;type:decimal(10,2);comment:时长(天)"`
	Status        int32         `json:"status" gorm:"column:status;type:int;comment:状态(目前和审批系统状态同步)"`
	ApprovalUsers ApprovalUsers `json:"approvalUsers" gorm:"column:approval_users;type:json;comment:审批人"`
	CopyUsers     CopyUsers     `json:"copyUsers" gorm:"column:copy_users;type:json;comment:抄送人"`
}

type VerifyFiles []string

type ApplyTime struct {
	Date string `json:"date"` // 日期 2023-05-08
	Hour string `json:"hour"` // 时间 09:00
	M    string `json:"m"`    // 上午|下午
}

type ApplyTimes []ApplyTime

var sonMap = map[string]string{
	"leave":            "leave", // 事假
	"sick":             "leave", // 病假
	"annualLeave":      "leave", // 年假
	"dayOff":           "leave", // 调休
	"maritalLeave":     "leave", // 婚假
	"matingCheckLeave": "leave", // 孕检假
	"maternityLeave":   "leave", // 产假
	"paternityLeave":   "leave", // 陪产假
	"parentalLeave":    "leave", // 育儿假
	"nursingLeave":     "leave", // 独生子女护理假
	"funeralLeave":     "leave", // 丧假

	"makeUp":   "makeUp",   // 补卡
	"overTime": "overTime", // 加班
	"outWork":  "outWork",  // 外勤
	"turnover": "turnover", // 离职

	"annualLeaveApply":      "leaveApply", // 年假申请
	"maritalLeaveApply":     "leaveApply", // 婚假申请
	"matingCheckLeaveApply": "leaveApply", // 孕检假申请
	"maternityLeaveApply":   "leaveApply", // 产假申请
	"paternityLeaveApply":   "leaveApply", // 陪产假申请
	"parentalLeaveApply":    "leaveApply", // 育儿假申请
	"nursingLeaveApply":     "leaveApply", // 独生子女护理假申请
}

// TableName get sql table name.获取数据库表名
func (oa *ApprovalOA) TableName() string {
	return "approval_oa"
}

func (oa *ApprovalOA) GetApproval(id uint64) (*Approval, error) {

	var entity *Approval
	if err := DB.
		Preload("ApprovalWorkFlows").
		Preload("ApprovalType").
		Preload("ApprovalOA").
		First(&entity, id).Error; err != nil {
		return entity, err
	}

	return entity, nil
}

func (oa *ApprovalOA) SaveApprovalContent(in *approval.CreateRequest, a *Approval) error {

	if err := oa.copyOAToModel(in, a); err != nil {
		return err
	}

	return DB.Create(&oa).Error
}

func (oa *ApprovalOA) copyOAToModel(in *approval.CreateRequest, a *Approval) error {
	copier.CopyWithOption(&oa, in.ApprovalOA, copier.Option{DeepCopy: true})
	oa.ApprovalID = a.ID

	if err := oa.addOtherInfoToModel(in, a); err != nil {
		return err
	}

	return nil
}

func (oa *ApprovalOA) addOtherInfoToModel(in *approval.CreateRequest, a *Approval) error {
	if v, ok := sonMap[a.ApprovalType.KeyWord]; ok {
		switch v {
		case "leave":
			oa.Leave.ApprovalUsers = a.ApprovalUsers
			oa.Leave.CopyUsers = a.CopyUsers
			if oa.Leave.ApplyType != "" {
				oa.Leave.ApplyType = a.ApprovalType.KeyWord
			}
			oa.Leave.ApprovalID = strconv.FormatUint(a.ID, 10)
			oa.Leave.Status = int32(a.Status)

			applyTimes := make([]ApplyTime, 0)
			for i := 0; i < len(in.ApprovalOA.Leave.ApplyTimes); i++ {
				applyTimes = append(applyTimes, ApplyTime{
					Date: in.ApprovalOA.Leave.ApplyTimes[i].Date,
					Hour: in.ApprovalOA.Leave.ApplyTimes[i].Hour,
					M:    in.ApprovalOA.Leave.ApplyTimes[i].M,
				})
			}
			oa.Leave.ApplyTimes = applyTimes
		case "makeUp":
			oa.MakeUp.ApprovalUsers = a.ApprovalUsers
			oa.MakeUp.CopyUsers = a.CopyUsers
			oa.MakeUp.ApplyType = a.ApprovalType.KeyWord
			oa.MakeUp.ApprovalID = strconv.FormatUint(a.ID, 10)
			oa.MakeUp.Status = int32(a.Status)

			applyTimes := make([]ApplyTime, 0)
			for i := 0; i < len(in.ApprovalOA.MakeUp.ApplyTimes); i++ {
				applyTimes = append(applyTimes, ApplyTime{
					Date: in.ApprovalOA.MakeUp.ApplyTimes[i].Date,
					Hour: in.ApprovalOA.MakeUp.ApplyTimes[i].Hour,
					M:    in.ApprovalOA.MakeUp.ApplyTimes[i].M,
				})
			}
			oa.MakeUp.ApplyTimes = applyTimes
		case "overTime":
			oa.OverTime.ApprovalUsers = a.ApprovalUsers
			oa.OverTime.CopyUsers = a.CopyUsers
			oa.OverTime.ApplyType = a.ApprovalType.KeyWord
			oa.OverTime.ApprovalID = strconv.FormatUint(a.ID, 10)
			oa.OverTime.Status = int32(a.Status)

			applyTimes := make([]ApplyTime, 0)
			for i := 0; i < len(in.ApprovalOA.OverTime.ApplyTimes); i++ {
				applyTimes = append(applyTimes, ApplyTime{
					Date: in.ApprovalOA.OverTime.ApplyTimes[i].Date,
					Hour: in.ApprovalOA.OverTime.ApplyTimes[i].Hour,
					M:    in.ApprovalOA.OverTime.ApplyTimes[i].M,
				})
			}
			oa.OverTime.ApplyTimes = applyTimes
		case "outWork":
			oa.OutWork.ApprovalUsers = a.ApprovalUsers
			oa.OutWork.CopyUsers = a.CopyUsers
			oa.OutWork.ApplyType = a.ApprovalType.KeyWord
			oa.OutWork.ApprovalID = strconv.FormatUint(a.ID, 10)
			oa.OutWork.Status = int32(a.Status)

			applyTimes := make([]ApplyTime, 0)
			for i := 0; i < len(in.ApprovalOA.OutWork.ApplyTimes); i++ {
				applyTimes = append(applyTimes, ApplyTime{
					Date: in.ApprovalOA.OutWork.ApplyTimes[i].Date,
					Hour: in.ApprovalOA.OutWork.ApplyTimes[i].Hour,
					M:    in.ApprovalOA.OutWork.ApplyTimes[i].M,
				})
			}
			oa.OutWork.ApplyTimes = applyTimes
		case "turnover":
			oa.Turnover.ApprovalUsers = a.ApprovalUsers
			oa.Turnover.CopyUsers = a.CopyUsers
			oa.Turnover.ApplyType = a.ApprovalType.KeyWord
			oa.Turnover.ApprovalID = strconv.FormatUint(a.ID, 10)
			oa.Turnover.Status = int32(a.Status)

			applyTimes := make([]ApplyTime, 0)
			for i := 0; i < len(in.ApprovalOA.Turnover.ApplyTimes); i++ {
				applyTimes = append(applyTimes, ApplyTime{
					Date: in.ApprovalOA.Turnover.ApplyTimes[i].Date,
					Hour: in.ApprovalOA.Turnover.ApplyTimes[i].Hour,
					M:    in.ApprovalOA.Turnover.ApplyTimes[i].M,
				})
			}
			oa.Turnover.ApplyTimes = applyTimes
		case "leaveApply":
			oa.LeaveApply.ApprovalUsers = a.ApprovalUsers
			oa.LeaveApply.CopyUsers = a.CopyUsers
			oa.LeaveApply.ApplyType = a.ApprovalType.KeyWord
			oa.LeaveApply.ApprovalID = strconv.FormatUint(a.ID, 10)
			oa.LeaveApply.Status = int32(a.Status)
		default:
			return errors.New("未找到相关审批类型")
		}
	}
	return nil
}

func (oa *ApprovalOA) UpdateApprovalContent(in *approval.CreateRequest, a *Approval) error {

	var entity *ApprovalOA

	if err := DB.Where(&ApprovalOA{ApprovalID: a.ID}).First(&entity).Error; err != nil {
		return errors.New(m2.ErrorNotFound)
	}

	oa.ID = entity.ID

	if err := oa.copyOAToModel(in, a); err != nil {
		return err
	}

	return DB.Model(&oa).Updates(oa).Error
}

func (oa *ApprovalOA) BuildResContent(a *Approval, request *approval.CreateRequest) {
	if err := oa.copyOAToRpc(a, request); err != nil {
		return
	}
}

func (oa *ApprovalOA) copyOAToRpc(a *Approval, in *approval.CreateRequest) error {
	copier.CopyWithOption(&in.ApprovalOA, a, copier.Option{DeepCopy: true})

	if err := oa.addOtherInfoToRpc(a, in); err != nil {
		return err
	}

	return nil
}

func (oa *ApprovalOA) addOtherInfoToRpc(a *Approval, in *approval.CreateRequest) error {
	if oa.Leave != nil {
		copier.CopyWithOption(&a.ApprovalOA.Leave.ApplyTimes, in.ApprovalOA.Leave.ApplyTimes, copier.Option{DeepCopy: true})
	}

	if oa.MakeUp != nil {
		copier.CopyWithOption(&a.ApprovalOA.MakeUp.ApplyTimes, in.ApprovalOA.MakeUp.ApplyTimes, copier.Option{DeepCopy: true})
	}

	if oa.Turnover != nil {
		copier.CopyWithOption(&a.ApprovalOA.Turnover.ApplyTimes, in.ApprovalOA.Turnover.ApplyTimes, copier.Option{DeepCopy: true})
	}

	if oa.OverTime != nil {
		copier.CopyWithOption(&a.ApprovalOA.OverTime.ApplyTimes, in.ApprovalOA.OverTime.ApplyTimes, copier.Option{DeepCopy: true})
	}

	if oa.OutWork != nil {
		copier.CopyWithOption(&a.ApprovalOA.OutWork.ApplyTimes, in.ApprovalOA.OutWork.ApplyTimes, copier.Option{DeepCopy: true})
	}

	return nil
}

func (oa *ApprovalOA) DeleteApproval(p *Approval) error {
	return DB.Where(&ApprovalOA{ApprovalID: p.ID}).Delete(&ApprovalOA{}).Error
}