package v1

import (
	"bytes"
	"context"
	"encoding/csv"
	"encoding/json"
	"net/http"
	"os"
	"strings"
	"time"

	"github.com/pingcap-inc/pchub/pkg/log"
	"github.com/spf13/viper"

	"github.com/pingcap-inc/security/internal/alert-server/store"
	v1 "github.com/pingcap-inc/security/model/v1"
)

type contractScanService struct {
	store store.Factory
}

type ContractScanSrv interface {
	FetchFromContract(ctx context.Context) error
	StartCheck(ctx context.Context)
}

var _ ContractScanSrv = (*contractScanService)(nil)

func newContractScan(srv *service) *contractScanService {
	return &contractScanService{store: srv.store}
}

func (s *contractScanService) StartCheck(ctx context.Context) {
	log.L(ctx).Info("StartCheck Called.")

	err := s.FetchFromContract(ctx)
	if err != nil {
		sdMsg(ctx)
		return
	}

	err = StartDuns(ctx)
	if err != nil {
		log.L(ctx).Errorf("StartDuns error: %v", err)

		sdMsg(ctx)
	}

	log.L(ctx).Info("Company Finished.")
}

func StartDuns(ctx context.Context) error {
	log.L(ctx).Info("StartDuns Called.")

	localDuns := "http://localhost:8868/inter/duns"

	// Authentication
	req, err := http.NewRequest("POST", localDuns, nil)
	if err != nil {
		log.L(ctx).Errorf("new request error: %v", err)
		return err
	}
	req.Header.Set("Authorization", "Bearer B5HjLO0BYiTxqxymgn5cYICYOGMk1UFb")

	client := &http.Client{}
	_, err = client.Do(req)
	if err != nil {
		log.L(ctx).Errorf("client do error: %v", err)
		return err
	}

	log.L(ctx).Info("Duns Finished.")

	return nil
}

func (s *contractScanService) FetchFromContract(ctx context.Context) error {
	log.L(ctx).Info("FetchFromContract Called.")

	url := "/contract/v1/contracts/search"
	// yesterday
	startDate := time.Now().AddDate(0, 0, -1).Format("2006-01-02 15:04:05")
	endDate := time.Now().Format("2006-01-02 15:04:05")
	body := &v1.ContractReqBody{
		PageSize:  1000,
		PageToken: "",
		CombineCondition: v1.CombineCondition{
			SubmittedTimeStart: startDate,
			SubmittedTimeEnd:   endDate,
		},
	}

	comSrv := newCommon()
	tk, _ := comSrv.GetLarkToken(ctx, qfeiType)

	results := make([]v1.ContractItems, 0)
	for {
		marshal, _ := json.Marshal(body)
		params := make(map[string]string)
		params["user_id_type"] = "user_id"

		resp, err := comSrv.GetDataByReqLarkAPI(ctx, "POST", QfeiOpenAPiBase+url, bytes.NewReader(marshal), params, tk)
		if err != nil {
			log.L(ctx).Errorf("post error: %v", err)
			return err
		}

		var commonResp respData
		err = json.Unmarshal(resp, &commonResp)
		if err != nil {
			log.L(ctx).Errorf("unmarshal error: %v", err)

			return err
		}

		var contractItems v1.ContractItems
		err = json.Unmarshal(resp, &contractItems)

		results = append(results, contractItems)

		if commonResp.PageToken == "" {
			body.PageToken = ""

			break
		}

		body.PageToken = commonResp.PageToken
	}

	records, err := s.store.Company().ListCompany(ctx)
	if err != nil {
		log.L(ctx).Errorf("list error: %v", err)

		return err
	}

	rdMap := make(map[string]v1.Company)
	for _, record := range records {
		rdMap[record.Name+record.Country] = record
	}

	ccMap, err := countryCodeMap(ctx)
	if err != nil {
		return err
	}

	addRecords := make([]v1.Company, 0)
	viaMap := make(map[string]bool)
	for _, result := range results {
		for _, item := range result.Items {
			for _, counterParty := range item.CounterPartyList {
				_, ok1 := rdMap[counterParty.CounterPartyName+ccMap[counterParty.RegisterAddress.Country]]
				_, ok2 := viaMap[counterParty.CounterPartyName+ccMap[counterParty.RegisterAddress.Country]]
				if !ok1 && !ok2 {
					if len(counterParty.CounterPartyName) <= 2 {
						continue
					}
					addRecords = append(addRecords, v1.Company{
						CreatedAt: time.Now(),
						Name:      counterParty.CounterPartyName,
						Country:   ccMap[counterParty.RegisterAddress.Country],
						Status:    0,
						From:      "新飞书合同",
					})

					viaMap[counterParty.CounterPartyName+ccMap[counterParty.RegisterAddress.Country]] = true
				}
			}
		}
	}

	for _, rd := range addRecords {
		err = s.store.Company().CreateCompanyOne(ctx, rd)
		if err != nil && !strings.Contains(err.Error(), "Duplicate entry") {
			log.L(ctx).Errorf("create error: %v", err)

			return err
		}
	}

	log.L(ctx).Info("FetchFromContract Company Finished.")

	return nil
}

func countryCodeMap(ctx context.Context) (map[string]string, error) {
	log.L(ctx).Info("countryCodeMap Called.")

	f, err := os.Open(viper.GetString("country-code-csv"))
	if err != nil {
		log.L(ctx).Errorf("open error: %v", err)

		return nil, err
	}
	defer f.Close()

	// 读取文件
	r := csv.NewReader(f)
	records, err := r.ReadAll()
	if err != nil {
		log.L(ctx).Errorf("read error: %v", err)

		return nil, err
	}

	ccMap := make(map[string]string)
	// 遍历并打印记录
	for _, record := range records {
		ccMap[record[1]] = record[0]
	}

	ccMap["中国大陆"] = "CN"
	ccMap["中国台湾"] = "TW"
	ccMap["中国香港"] = "HK"
	ccMap["中国澳门"] = "MO"

	log.L(ctx).Info("countryCodeMap Finished.")

	return ccMap, nil
}

func sdMsg(ctx context.Context) {
	ct := TextMessage{
		Text: "Company search program has error, please check.",
	}

	marshal, _ := json.Marshal(ct)

	_, err := SendLarkMsg(ctx, "user_id", MessageBody{
		MsgType:   "text",
		Content:   string(marshal),
		ReceiveID: primaryNotificationLarkUserID,
	})
	if err != nil {
		log.L(ctx).Errorf("error when send lark msg, err: %s", err.Error())
	}
}
