package gameShield

import (
	"context"
	"fmt"
	v1 "github.com/go-nunu/nunu-layout-advanced/api/v1"
	"github.com/go-nunu/nunu-layout-advanced/internal/model"
	"github.com/go-nunu/nunu-layout-advanced/internal/repository"
	"github.com/go-nunu/nunu-layout-advanced/internal/service"
	"github.com/spf13/viper"
	"strconv"
	"time"
)

type GameShieldService interface {
	SubmitGameShield(ctx context.Context, req *v1.GameShieldSubmitRequest) (string, error)
	EditGameShield(ctx context.Context, req *v1.GameShieldSubmitRequest) (string, error)
	DeleteGameShield(ctx context.Context, req int) (string, error)
	GetGameShieldKey(ctx context.Context, id int) (string, error)
	GetKeyAndEditGameShield(ctx context.Context, hostId int, dunName string) (string, error)
	GetGameShieldOnlineList(ctx context.Context, hostId int) ([]v1.SDKInfo, error)
	IsExistGameShieldKey(ctx context.Context, key string) (string, error)
}

func NewGameShieldService(
	service *service.Service,
	gameShieldRepository repository.GameShieldRepository,
	crawlerService service.CrawlerService,
	gameShieldPublicIpService service.GameShieldPublicIpService,
	duedate service.DuedateService,
	formatter service.FormatterService,
	parser service.ParserService,
	required service.RequiredService,
	conf *viper.Viper,
	gameShieldSdkIp service.GameShieldSdkIpService,
) GameShieldService {
	return &gameShieldService{
		Service:                   service,
		gameShieldRepository:      gameShieldRepository,
		crawlerService:            crawlerService,
		gameShieldPublicIpService: gameShieldPublicIpService,
		duedate:                   duedate,
		formatter:                 formatter,
		parser:                    parser,
		required:                  required,
		Url:                       conf.GetString("crawler.Url"),
		gameShieldSdkIp:           gameShieldSdkIp,
	}
}

type gameShieldService struct {
	*service.Service
	config                    *viper.Viper
	crawlerService            service.CrawlerService
	gameShieldRepository      repository.GameShieldRepository
	gameShieldPublicIpService service.GameShieldPublicIpService
	duedate                   service.DuedateService
	formatter                 service.FormatterService
	Url                       string
	parser                    service.ParserService
	required                  service.RequiredService
	gameShieldSdkIp           service.GameShieldSdkIpService
}

func (service *gameShieldService) SubmitGameShield(ctx context.Context, req *v1.GameShieldSubmitRequest) (string, error) {
	nameCount, err := service.gameShieldRepository.GetGameShieldDuplicateName(ctx, req.AppName, req.Uid)
	if err != nil {
		return "", err
	}
	if nameCount > 0 {
		return "", fmt.Errorf("应用名称已存在")
	}

	// 调用IP生成服务
	if err := service.gameShieldSdkIp.GenerateMultipleLoopbackIps(ctx, req.Uid, req.HostId); err != nil {
		return "", fmt.Errorf("生成IP地址失败: %w", err)
	}

	dunName := strconv.Itoa(req.Uid) + "_hostId" + strconv.Itoa(req.HostId) + "_" + req.Domain
	formData := map[string]interface{}{
		"app_name":         dunName,
		"gateway_group_id":  2, // TODO: 临时写死
		"backend":          "{}",
		"expired_at":       "",
		"max_device_count": 0,
	}
	respBody, err := service.required.SendForm(ctx, "admin/info/rule/new", "admin/new/rule", formData)
	if err != nil {
		return "", err
	}
	// 解析响应内容中的 alert 消息
	res, err := service.parser.ParseAlert(string(respBody))
	if err != nil {
		return "", err
	}
	if res != "" {
		return "", fmt.Errorf(res)
	}
	KeyAndField, err := service.required.GetKeyAndField(ctx, dunName, "rule_id")
	if err != nil {
		return "", err
	}
	if err := service.gameShieldRepository.AddGameShield(ctx, &model.GameShield{
		AppName:        req.AppName,
		GatewayGroupId: 2,	// TODO: 临时写死
		AddTime:        time.Now(),
		Uid:            req.Uid,
		HostId:         req.HostId,
		DunName:        dunName,
		RuleId:         KeyAndField.FieldId,
	}); err != nil {
		return "", err
	}

	return "", nil
}

func (service *gameShieldService) EditGameShield(ctx context.Context, req *v1.GameShieldSubmitRequest) (string, error) {
	if err := service.gameShieldRepository.UpdateGameShield(ctx, &model.GameShield{
		HostId:  req.HostId,
		AppName: req.AppName,
	}); err != nil {
		return "", err
	}
	return "", nil
}

func (service *gameShieldService) DeleteGameShield(ctx context.Context, id int) (string, error) {
	shieldInfo, err := service.gameShieldRepository.GetGameShieldById(ctx, int64(id))
	if err != nil {
		return "", err
	}
	if err := service.gameShieldRepository.DeleteGameShield(ctx, shieldInfo.RuleId); err != nil {
		return "", err
	}
	res, err := service.crawlerService.DeleteRule(ctx, shieldInfo.RuleId, "admin/delete/rule?page=1&__pageSize=10&__sort=rule_id&__sort_type=desc")
	if err != nil {
		return "", err
	}

	return res, nil
}

func (service *gameShieldService) GetGameShieldKey(ctx context.Context, hostId int) (string, error) {
	dunName, err := service.gameShieldRepository.GetGameShieldHostIdByDunName(ctx, strconv.Itoa(hostId))
	if err != nil {
		return "", err
	}
	if dunName == "" {
		return "", fmt.Errorf("暂无数据")
	}
	res, err := service.crawlerService.GetKey(ctx, dunName)
	if err != nil {
		return "", err
	}
	return res, nil
}

func (service *gameShieldService) GetKeyAndEditGameShield(ctx context.Context, hostId int, dunName string) (string, error) {
	key, err := service.crawlerService.GetKey(ctx, dunName)
	if err != nil {
		return "", err
	}

	if err := service.gameShieldRepository.UpdateGameShield(ctx, &model.GameShield{
		HostId: hostId,
		Key:    key,
	}); err != nil {
		return "", err
	}
	return "", nil
}

func (service *gameShieldService) GetGameShieldOnlineList(ctx context.Context, hostId int) ([]v1.SDKInfo, error) {
	strHostId := strconv.Itoa(hostId)
	cookie, err := service.required.Required(ctx)
	if err != nil {
		return nil, err
	}
	respBody, err := service.crawlerService.FetchPageContent(ctx, "admin/sdk/online?rule_id="+strHostId, cookie)
	if err != nil {
		return nil, err
	}
	res, err := service.parser.ParseSDKOnlineHTMLTable(string(respBody))
	if err != nil {
		return nil, err
	}
	if len(res) == 0 {
		return nil, fmt.Errorf("暂无数据")
	}
	return res, nil
}

func (service *gameShieldService) IsExistGameShieldKey(ctx context.Context, key string) (string, error) {
	cookie, err := service.required.Required(ctx)
	if err != nil {
		return "", err
	}

	respBody, err := service.crawlerService.FetchPageContent(ctx, "admin/info/rule", cookie)
	if err != nil {
		return "", err
	}

	if err := service.parser.CheckSDKKeyStatus(string(respBody), key); err != nil {

		return "", err
	}
	return "", nil
}
