package service

import (
	butil "enterprise/base/util"
	"enterprise/common/config"
	"enterprise/common/dao"
	"enterprise/common/model"
	"enterprise/server/api"
	"enterprise/server/session"
	"fmt"
	"github.com/gin-gonic/gin"
	log "github.com/sirupsen/logrus"
	"github.com/spf13/cast"
	excelize "github.com/xuri/excelize/v2"
	"os"
	"sort"
	"time"

	"net/http"
)

var (
	StaffSalaryTypeBank    = "bank"
	StaffSalaryTypeSummary = "summary"
	StaffSalaryTypeAgent   = "agent"
)

type StaffSalary struct {
}

func NewStaffSalary() *StaffSalary {
	return &StaffSalary{}
}

func (s *StaffSalary) List(sess *session.AdminSession, req *api.ListSalaryReq) (int64, interface{}, interface{}) {
	salarys, total, err := dao.NewStaffSalaryDao().QueryAdmin(1, -1, sess.GetCorpId(), req.Username, req.StartMonth, req.EndMonth)
	session.CheckDBError(err)
	start := (req.Page - 1) * req.Size
	end := start + req.Size

	items := make([]*api.Salary, 0)
	summary := new(api.Salary)
	for pos, m := range salarys {
		staffSalary := new(api.Salary)
		staffSalary.From(m)
		summary.Add(staffSalary)
		if pos < start || pos >= end {
			continue
		}
		staffUser, err := dao.NewStaffUserDao().Get(m.UserId)
		session.CheckDBError(err)
		if staffUser != nil {
			userSalary := staffUser.GetSalary()
			staffSalary.Realname = staffUser.Realname
			staffSalary.TargetSalary = userSalary.Target
			staffSalary.BaseSalary = userSalary.Base
		}
		items = append(items, staffSalary)
	}

	return total, summary, items
}

func (s *StaffSalary) Create(sess *session.AdminSession, req *api.CreateSalaryReq) {
	return
}

func (s *StaffSalary) Update(sess *session.AdminSession, req *api.UpdateSalaryReq) {
	salary, err := dao.NewStaffSalaryDao().Get(cast.ToInt64(req.Id))
	session.CheckDBError(err)
	session.CheckNilError(salary, "工资单不存在")
	if req.OtherSalary != "" {
		salary.OtherSalary = cast.ToFloat64(req.OtherSalary)
	}
	if req.OtherDeduct != "" {
		salary.OtherDeduct = cast.ToFloat64(req.OtherDeduct)
	}
	err = dao.NewStaffSalaryDao().Update(salary)
	session.CheckDBError(err)
}

func (s *StaffSalary) Agent(cid int64, month string, ctx *gin.Context) {
	xls := ctx.Query("xls")
	staffSalarys, err := dao.NewStaffSalaryDao().QueryAll(cid, month)
	if err != nil {
		panic(config.ErrDb.New().Append(err))
	}

	header := []string{"姓名", "身份证号", "电话", "应发工资", "社保扣除", "公积金扣除", "个税扣除", "实发工资"}
	datas := make([][]string, 0)
	for _, staff := range staffSalarys {
		userInfo, err := dao.NewStaffUserDao().Get(staff.UserId)
		if err != nil {
			log.Errorf("db error :%s", err.Error())
			continue
		}
		if userInfo == nil {
			continue
		}
		userSalary := userInfo.GetSalary()
		if userSalary.Base == "" {
			continue
		}
		item := make([]string, 0)

		item = append(item, userInfo.Realname)
		item = append(item, cast.ToString(userInfo.Idno))
		item = append(item, cast.ToString(userInfo.Phone))
		item = append(item, cast.ToString(staff.GetShouldSalary()))
		item = append(item, cast.ToString(staff.SocialDeduct))
		item = append(item, cast.ToString(staff.HouseDeduct))
		item = append(item, cast.ToString(staff.PersonalDeduct))
		item = append(item, cast.ToString(staff.GetRealSalary()))

		datas = append(datas, item)
	}

	if xls != "" {
		filename := fmt.Sprintf("agent_%s.xlsx", time.Now().Format("20060102_150405"))
		s.toExcel(filename, header, datas, ctx)
		os.Remove(filename)
	} else {
		links := make([]map[string]string, 0)
		links = append(links, map[string]string{
			"url":  "/staff/salary?type=agent&xls=1&cid=" + cast.ToString(cid),
			"name": "下载",
		})
		links = append(links, map[string]string{
			"url":  "/staff/salary?type=bank&cid=" + cast.ToString(cid),
			"name": "银行",
		})
		links = append(links, map[string]string{
			"url":  "/staff/salary?type=summary&cid=" + cast.ToString(cid),
			"name": "汇总",
		})
		ctx.HTML(http.StatusOK, "salary.html", gin.H{
			"title":  month + "工资汇总",
			"header": header,
			"data":   datas,
			"link":   links,
		})
	}
}

func (s *StaffSalary) Bank(cid int64, month string, ctx *gin.Context) {
	xls := ctx.Query("xls")
	staffSalarys, err := dao.NewStaffSalaryDao().QueryAll(cid, month)
	if err != nil {
		panic(config.ErrDb.New().Append(err))
	}

	header := []string{"账号", "户名", "金额", "开户行", "开户地", "收款备注"}
	datas := make([][]string, 0)
	for _, staff := range staffSalarys {
		userInfo, err := dao.NewStaffUserDao().Get(staff.UserId)
		if err != nil {
			log.Errorf("db error :%s", err.Error())
			continue
		}
		if userInfo == nil {
			continue
		}
		userSalary := userInfo.GetSalary()
		userPayee := userInfo.GetPayee()
		if userSalary.Base == "" {
			continue
		}

		item := make([]string, 0)
		item = append(item, userPayee.BankCard)
		item = append(item, userInfo.Realname)
		item = append(item, cast.ToString(staff.GetRealSalary()))
		item = append(item, cast.ToString(userPayee.BankName))
		item = append(item, "重庆市")
		item = append(item, fmt.Sprintf("%s工资", month))
		datas = append(datas, item)
	}

	if xls != "" {
		filename := fmt.Sprintf("bank_%s.xlsx", time.Now().Format("20060102_150405"))
		s.toExcel(filename, header, datas, ctx)
		os.Remove(filename)
	} else {
		links := make([]map[string]string, 0)
		links = append(links, map[string]string{
			"url":  "/staff/salary?type=bank&xls=1&cid=" + cast.ToString(cid),
			"name": "下载",
		})
		links = append(links, map[string]string{
			"url":  "/staff/salary?type=summary&cid=" + cast.ToString(cid),
			"name": "汇总",
		})
		links = append(links, map[string]string{
			"url":  "/staff/salary?type=agent&cid=" + cast.ToString(cid),
			"name": "代理",
		})
		ctx.HTML(http.StatusOK, "salary.html", gin.H{
			"title":  month + "工资汇总",
			"header": header,
			"data":   datas,
			"link":   links,
		})
	}
}

func (s *StaffSalary) Summary(cid int64, month string, ctx *gin.Context) {
	xls := ctx.Query("xls")
	staffSalarys, err := dao.NewStaffSalaryDao().QueryAll(cid, month)
	if err != nil {
		panic(config.ErrDb.New().Append(err))
	}
	sort.Sort(model.StaffSalarySort(staffSalarys))

	var header []string
	if cid == 1002 {
		header = []string{"姓名", "入职日期", "转正日期", "基本工资", "绩效工资", "出勤收入", "绩效收入", "奖金收入", "其他收入", "应出勤天数", "实际出勤天数", "请假天数", "实发工资", "状态"}
	} else {
		header = []string{"姓名", "入职日期", "转正日期", "基本工资", "绩效工资", "出勤收入", "绩效收入", "奖金收入", "其他收入", "社保扣除", "公积金扣除",
			"个税扣除", "应出勤天数", "实际出勤天数", "请假天数", "实发工资", "状态"}
	}
	datas := make([][]string, 0)
	summary := new(model.StaffSalary)
	totalCount := 0
	for _, salary := range staffSalarys {
		userInfo, err := dao.NewStaffUserDao().Get(salary.UserId)
		if err != nil {
			log.Errorf("db error :%s", err.Error())
			continue
		}
		if userInfo == nil {
			continue
		}
		userSalary := userInfo.GetSalary()
		//extra := make(map[string]interface{})
		//json.Unmarshal([]byte(salary.Extra), &extra)
		item := make([]string, 0)
		item = append(item, userInfo.Realname)
		item = append(item, cast.ToString(userInfo.EntryDate))
		item = append(item, cast.ToString(userInfo.OfficialDate))
		item = append(item, userSalary.Base)
		item = append(item, userSalary.Target)
		item = append(item, cast.ToString(butil.FloatCut(salary.AttendSalary)))
		item = append(item, cast.ToString(butil.FloatCut(salary.TargetSalary)))
		item = append(item, cast.ToString(butil.FloatCut(salary.AwardSalary)))
		item = append(item, cast.ToString(butil.FloatCut(salary.OtherSalary)))

		if cid != 1002 {
			item = append(item, cast.ToString(butil.FloatCut(salary.SocialDeduct)))
			item = append(item, cast.ToString(butil.FloatCut(salary.HouseDeduct)))
			item = append(item, cast.ToString(butil.FloatCut(salary.PersonalDeduct)))
		}
		item = append(item, cast.ToString(salary.ShouldDay))

		item = append(item, cast.ToString(butil.FloatCut(salary.AttendDay)))
		item = append(item, cast.ToString(butil.FloatCut(salary.HolidayDay)))
		item = append(item, cast.ToString(salary.GetRealSalary()))
		if cast.ToFloat64(salary.ShouldDay) != cast.ToFloat64(salary.AttendDay)+cast.ToFloat64(salary.HolidayDay) {
			item = append(item, "【异常】")
		} else {
			item = append(item, "")
		}

		totalCount += 1

		datas = append(datas, item)
		summary.Salary += salary.Salary

		summary.TargetSalary += salary.TargetSalary
		summary.AttendSalary += salary.AttendSalary
		summary.AwardSalary += salary.AwardSalary
		summary.OtherSalary += salary.OtherSalary

		summary.SocialDeduct += salary.SocialDeduct
		summary.HouseDeduct += salary.HouseDeduct
		summary.PersonalDeduct += salary.PersonalDeduct
		summary.OtherDeduct += salary.OtherDeduct
		summary.AttendDay += salary.AttendDay
		summary.HolidayDay += salary.HolidayDay
	}
	summary.HolidayDay = butil.FloatCut(summary.HolidayDay)
	summary.Salary = butil.FloatCut(summary.Salary)
	summary.TargetSalary = butil.FloatCut(summary.TargetSalary)
	summary.AttendSalary = butil.FloatCut(summary.AttendSalary)
	summary.AwardSalary = butil.FloatCut(summary.AwardSalary)
	summary.SocialDeduct = butil.FloatCut(summary.SocialDeduct)
	summary.HouseDeduct = butil.FloatCut(summary.HouseDeduct)
	summary.PersonalDeduct = butil.FloatCut(summary.PersonalDeduct)
	summary.OtherDeduct = butil.FloatCut(summary.OtherDeduct)

	if cid != 1002 {
		datas = append(datas, []string{"合计", cast.ToString(totalCount), "-",
			cast.ToString(summary.Salary), "-", cast.ToString(summary.AttendSalary), cast.ToString(summary.TargetSalary), cast.ToString(summary.AwardSalary), cast.ToString(summary.OtherSalary),
			cast.ToString(summary.SocialDeduct), cast.ToString(summary.HouseDeduct), cast.ToString(summary.PersonalDeduct),
			"-", "-", cast.ToString(summary.HolidayDay),
			cast.ToString(butil.FloatCut(summary.GetRealSalary())), "-"})
	} else {
		datas = append(datas, []string{"合计", cast.ToString(totalCount), "-",
			cast.ToString(summary.Salary), "-", cast.ToString(summary.AttendSalary), cast.ToString(summary.TargetSalary), cast.ToString(summary.AwardSalary), cast.ToString(summary.OtherSalary),
			"-", "-", cast.ToString(summary.HolidayDay),
			cast.ToString(butil.FloatCut(summary.GetRealSalary())), "-"})
	}

	if xls != "" {
		filename := fmt.Sprintf("summary_%s.xlsx", time.Now().Format("20060102_150405"))
		s.toExcel(filename, header, datas, ctx)
		os.Remove(filename)
	} else {
		links := make([]map[string]string, 0)
		links = append(links, map[string]string{
			"url":  "/staff/salary?type=bank&cid=" + cast.ToString(cid),
			"name": "银行",
		})
		links = append(links, map[string]string{
			"url":  "/staff/salary?type=agent&cid=" + cast.ToString(cid),
			"name": "代理",
		})
		ctx.HTML(http.StatusOK, "salary.html", gin.H{
			"title":  month + "工资汇总",
			"header": header,
			"data":   datas,
			"link":   links,
		})
	}
}

func (s *StaffSalary) toExcel(filePath string, header []string, datas [][]string, ctx *gin.Context) {
	f := excelize.NewFile()
	//声明工作表的名称
	sheetName := "工资单"
	f.SetSheetName("Sheet1", sheetName)

	f.SetSheetRow(sheetName, "A1", &header)
	for i, data := range datas {
		f.SetSheetRow(sheetName, fmt.Sprintf("A%d", i+2), &data)
	}
	if err := f.SaveAs(filePath); err != nil {
		panic(config.ErrInternal.New().Append(err))
	}

	ctx.Writer.Header().Add("Content-Disposition", fmt.Sprintf("attachment; filename=%s", filePath))
	ctx.Writer.Header().Add("Content-Type", "application/msexcel")
	ctx.File(filePath)
}