package waf

import (
	"context"
	"encoding/json"
	"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/api/waf"
	"github.com/go-nunu/nunu-layout-advanced/internal/service"
	"github.com/go-nunu/nunu-layout-advanced/internal/service/api/flexCdn"
	"github.com/go-nunu/nunu-layout-advanced/pkg/rabbitmq"
	"golang.org/x/sync/errgroup"
	"maps"
	"net"
	"sort"
)

type WebForwardingService interface {
	GetWebForwarding(ctx context.Context, req v1.GetForwardingRequest) (v1.WebForwardingDataRequest, error)
	GetWebForwardingWafWebAllIps(ctx context.Context, req v1.GetForwardingRequest) ([]v1.WebForwardingDataRequest, error)
	AddWebForwarding(ctx context.Context, req *v1.WebForwardingRequest) (int, error)
	EditWebForwarding(ctx context.Context, req *v1.WebForwardingRequest) error
	DeleteWebForwarding(ctx context.Context, req v1.DeleteWebForwardingRequest) error
}

func NewWebForwardingService(
	service *service.Service,
	required service.RequiredService,
	webForwardingRepository waf.WebForwardingRepository,
	crawler service.CrawlerService,
	parser service.ParserService,
	wafformatter WafFormatterService,
	aoDun service.AoDunService,
	mq *rabbitmq.RabbitMQ,
	gatewayIp GatewayipService,
	globalLimitRep waf.GlobalLimitRepository,
	cdn flexCdn.CdnService,
	proxy flexCdn.ProxyService,
	sslCert flexCdn.SslCertService,
	websocket flexCdn.WebsocketService,
	cc CcService,
	ccIpList CcIpListService,
) WebForwardingService {
	return &webForwardingService{
		Service:                 service,
		webForwardingRepository: webForwardingRepository,
		required:                required,
		parser:                  parser,
		crawler:                 crawler,
		wafformatter:            wafformatter,
		aoDun:                   aoDun,
		mq:                      mq,
		gatewayIp:               gatewayIp,
		cdn:                     cdn,
		globalLimitRep:          globalLimitRep,
		proxy:                   proxy,
		sslCert:               	 sslCert,
		websocket:               websocket,
		cc:                      cc,
		ccIpList:                ccIpList,
	}
}

const (
	isHttps              = 1
	protocolHttps        = "https"
	protocolHttp         = "http"
)

type webForwardingService struct {
	*service.Service
	webForwardingRepository waf.WebForwardingRepository
	required                service.RequiredService
	parser                  service.ParserService
	crawler                 service.CrawlerService
	wafformatter            WafFormatterService
	aoDun                   service.AoDunService
	mq                      *rabbitmq.RabbitMQ
	gatewayIp      GatewayipService
	cdn            flexCdn.CdnService
	globalLimitRep waf.GlobalLimitRepository
	proxy          flexCdn.ProxyService
	sslCert        flexCdn.SslCertService
	websocket flexCdn.WebsocketService
	cc        CcService
	ccIpList  CcIpListService
}

func (s *webForwardingService) require(ctx context.Context, req v1.GlobalRequire) (v1.GlobalRequire, error) {
	var err error
	var res v1.GlobalRequire
	g, gCtx := errgroup.WithContext(ctx)

	//g.Go(func() error {
	//	result, e := s.wafformatter.require(gCtx, req, "web")
	//	if e != nil {
	//		return e
	//	}
	//	res = result
	//	return nil
	//})

	g.Go(func() error {
		e := s.wafformatter.validateWafDomainCount(gCtx, req)
		if e != nil {
			return e
		}
		return nil
	})
	if err = g.Wait(); err != nil {
		return v1.GlobalRequire{}, err
	}
	return res, nil
}

func (s *webForwardingService) GetWebForwarding(ctx context.Context, req v1.GetForwardingRequest) (v1.WebForwardingDataRequest, error) {
	var webForwarding model.WebForwarding
	var backend model.WebForwardingRule
	g, gCtx := errgroup.WithContext(ctx)
	g.Go(func() error {
		res, e := s.webForwardingRepository.GetWebForwarding(gCtx, int64(req.Id))
		if e != nil {
			// 直接返回错误，errgroup 会捕获它
			return fmt.Errorf("GetWebForwarding failed: %w", e)
		}
		if res != nil {
			webForwarding = *res
		}
		return nil
	})

	g.Go(func() error {
		res, e := s.webForwardingRepository.GetWebForwardingIpsByID(ctx, req.Id)
		if e != nil {
			return fmt.Errorf("GetWebForwardingByID failed: %w", e)
		}
		if res != nil {
			backend = *res
		}
		return nil
	})

	if err := g.Wait(); err != nil {
		return v1.WebForwardingDataRequest{}, err
	}

	return v1.WebForwardingDataRequest{
		Id:          webForwarding.Id,
		Port:        webForwarding.Port,
		Domain:      webForwarding.Domain,
		IsHttps:     webForwarding.IsHttps,
		Comment:     webForwarding.Comment,
		BackendList: backend.BackendList,
		HttpsKey:    webForwarding.HttpsKey,
		HttpsCert:   webForwarding.HttpsCert,
		Proxy:       webForwarding.Proxy,
		CcConfig:    v1.CcConfigRequest{
			IsOn:            webForwarding.Cc,
			ThresholdMethod: webForwarding.ThresholdMethod,
			Level:           webForwarding.Level,
			Limit5s:         webForwarding.Limit5s,
			Limit60s:        webForwarding.Limit60s,
			Limit300s:       webForwarding.Limit300s,
		},
	}, nil
}

// buildWebForwardingModel 辅助函数，用于构建通用的 WebForwarding 模型
// ruleId 是从 WAF 系统获取的 ID
func (s *webForwardingService) buildWebForwardingModel(req *v1.WebForwardingDataRequest, ruleId int, require RequireResponse) *model.WebForwarding {
	return &model.WebForwarding{
		HostId:          require.HostId,
		CdnWebId:        ruleId,
		Port:            req.Port,
		Domain:          req.Domain,
		IsHttps:         req.IsHttps,
		Comment:         req.Comment,
		HttpsCert:       req.HttpsCert,
		HttpsKey:        req.HttpsKey,
		SslCertId:       int(req.SslCertId),
		SslPolicyId: int(req.SslPolicyId),
		Cc:              req.CcConfig.IsOn,
		ThresholdMethod: req.CcConfig.ThresholdMethod,
		Level:           req.CcConfig.Level,
		Limit5s:         req.CcConfig.Limit5s,
		Limit60s:        req.CcConfig.Limit60s,
		Limit300s:       req.CcConfig.Limit300s,
		Proxy:           req.Proxy,
	}
}

func (s *webForwardingService) buildWebRuleModel(reqData *v1.WebForwardingDataRequest, require RequireResponse, localDbId int, cdnOriginIds map[string]int64) *model.WebForwardingRule {
	return &model.WebForwardingRule{
		Uid:          require.Uid,
		HostId:       require.HostId,
		WebId:        localDbId,
		CdnOriginIds: cdnOriginIds,
		BackendList:  reqData.BackendList,
	}
}

// =================================================================
// 主函数：prepareWafData
// 职责：协调整个流程，负责获取前置配置和组装最终的 formData。
// =================================================================
func (s *webForwardingService) prepareWafData(ctx context.Context, req *v1.WebForwardingRequest) (RequireResponse, v1.Website, error) {
	// 1. 获取基础配置
	require, err := s.wafformatter.Require(ctx, v1.GlobalRequire{
		HostId:  req.HostId,
		Uid:     req.Uid,
		Comment: req.WebForwardingData.Comment,
	})
	if err != nil {
		return RequireResponse{}, v1.Website{}, fmt.Errorf("获取WAF前置配置失败: %w", err)
	}
	if require.Uid == 0 {
		return RequireResponse{}, v1.Website{}, fmt.Errorf("请先配置实例")
	}

	// 2. 调用辅助函数，构建核心的代理配置 (将复杂逻辑封装起来)
	byteData,  err := s.buildProxyConfig(ctx, req, require)
	if err != nil {
		return RequireResponse{}, v1.Website{}, err // 错误信息在辅助函数中已经包装好了
	}
	type serverNames struct {
		ServerNames string `json:"name" form:"name"`
		Type        string `json:"type" form:"type"`
	}
	var serverName []serverNames
	var serverJson []byte
	if req.WebForwardingData.Domain != "" {
		serverName = append(serverName, serverNames{
			ServerNames: req.WebForwardingData.Domain,
			Type:        "full",
		})
		serverJson, err = json.Marshal(serverName)
		if err != nil {
			return RequireResponse{}, v1.Website{}, err
		}
	}



	// 3. 组装最终的 WAF 表单数据
	formData := v1.Website{
		UserId:          int64(require.CdnUid),
		Type:            "httpProxy",
		Name:            require.Tag,
		ServerNamesJSON: serverJson,
		Description:     req.WebForwardingData.Comment,
		ServerGroupIds:  []int64{int64(require.GroupId)},
		NodeClusterId:   2,
	}


	// 4. 根据协议类型，填充 HttpJSON 和 HttpsJSON 字段
	if req.WebForwardingData.IsHttps == isHttps {
		formData.HttpJSON = v1.TypeJSON{IsOn: false}
		formData.HttpsJSON = byteData
	} else {
		formData.HttpJSON = byteData
		formData.HttpsJSON = v1.TypeJSON{IsOn: false}
	}

	return require, formData, nil
}

// =================================================================
// 辅助函数：buildProxyJSONConfig
// 职责：专门负责处理 HTTP/HTTPS 的差异，并生成对应的 JSON 配置。
// =================================================================
func (s *webForwardingService) buildProxyConfig(ctx context.Context, req *v1.WebForwardingRequest, require RequireResponse) (v1.TypeJSON, error) {
	var (
		jsonData v1.TypeJSON
		apiType  string

	)

	jsonData.IsOn = true
	apiType = protocolHttps
	jsonData.SslPolicyRef.SslPolicyId = req.WebForwardingData.SslPolicyId
	// 判断协议类型，并处理 HTTPS 的特殊逻辑（证书）
	if req.WebForwardingData.IsHttps == isHttps {
		// 处理证书信息
		if jsonData.SslPolicyRef.SslPolicyId == 0 {
			sslPolicyId, err := s.sslCert.AddSslPolicy(ctx, nil)
			if err != nil {
				return v1.TypeJSON{}, err
			}
			jsonData.SslPolicyRef.SslPolicyId = sslPolicyId
		}
		jsonData.SslPolicyRef.IsOn = true
	} else {
		apiType = protocolHttp
		jsonData.SslPolicyRef = v1.SslPolicyRef{
			IsOn: false,
			SslPolicyId: req.WebForwardingData.SslCertId,
		}
	}

	// 填充通用的 Listen 配置
	for _, v := range require.GatewayIps {
		jsonData.Listen = append(jsonData.Listen, v1.Listen{
			Protocol: apiType,
			Host:     v,
			Port:     req.WebForwardingData.Port,
		})
	}


	return jsonData, nil
}

// 查找两个列表的差异
func (s webForwardingService) FindDifferenceList(oldList, newList []v1.BackendList) (added, removed []v1.BackendList) {
	diff := make(map[v1.BackendList]int)

	// 1. 遍历旧列表，为每个元素计数 +1
	for _, item := range oldList {
		diff[item]++
	}

	// 2. 遍历新列表，为每个元素计数 -1
	for _, item := range newList {
		diff[item]--
	}

	// 3. 遍历 diff map 来找出差异
	for item, count := range diff {
		if count > 0 {
			// 如果 count > 0，说明这个元素在 oldList 中但不在 newList 中
			removed = append(removed, item)
		} else if count < 0 {
			// 如果 count < 0，说明这个元素在 newList 中但不在 oldList 中
			added = append(added, item)
		}
		// 如果 count == 0，说明元素在两个列表中都存在，不做任何操作
	}

	return added, removed
}

func (s *webForwardingService) AddWebForwarding(ctx context.Context, req *v1.WebForwardingRequest) (int, error) {
	require, formData, err := s.prepareWafData(ctx, req)
	if err != nil {
		return 0, err
	}

	// 验证域名限制
	err = s.wafformatter.validateWafDomainCount(ctx, v1.GlobalRequire{
		HostId: req.HostId,
		Domain: req.WebForwardingData.Domain,
		Comment: req.WebForwardingData.Comment,
		Uid: req.Uid,
	})
	if err != nil {
		return 0, err
	}

	err = s.wafformatter.validateWafPortCount(ctx, require.HostId)
	if err != nil {
		return 0, err
	}

	var protocol string
	if req.WebForwardingData.IsHttps == isHttps {
		protocol = "https"
	}else{
		protocol = "http"
	}
	// 验证端口重复
	err = s.wafformatter.VerifyPort(ctx, protocol, int64(req.WebForwardingData.Id), req.WebForwardingData.Port, int64(require.HostId), req.WebForwardingData.Domain)
	if err != nil {
		return 0, err
	}


	// 添加证书
	if req.WebForwardingData.IsHttps == isHttps {
		sslCertId, err := s.sslCert.AddSSLCert(ctx, v1.SSL{
			Name:         req.WebForwardingData.Domain,
			Domain:       req.WebForwardingData.Domain,
			CertData:     req.WebForwardingData.HttpsCert,
			KeyData:      req.WebForwardingData.HttpsKey,
			CdnUserId:    require.CdnUid,
			Description:  req.WebForwardingData.Comment,
		})
		if err != nil {
			return 0, err
		}
		req.WebForwardingData.SslCertId = sslCertId
		req.WebForwardingData.SslPolicyId = formData.HttpsJSON.SslPolicyRef.SslPolicyId
		err = s.sslCert.EditSslPolicy(ctx, formData.HttpsJSON.SslPolicyRef.SslPolicyId, []int64{sslCertId}, "add")
		if err != nil {
			return 0, err
		}
	}


	// 添加网站
	formDataSend, err := s.BulidFormData(ctx, formData)
	if err != nil {
		return 0, err
	}

	webId, err := s.cdn.CreateWebsite(ctx, formDataSend)
	if err != nil {
		return 0, err
	}
	backendList := make(map[string]string)
	for _, k := range req.WebForwardingData.BackendList {
		backendList[k.Addr] = k.CustomHost
	}


	// 开启websocket
	websocketId, err := s.websocket.AddWebsocket(ctx)
	if err != nil {
		return 0, err
	}
	if err := s.websocket.EnableOrDisable(ctx, webId, websocketId, true, false); err != nil {
		return 0, err
	}


	// 添加源站
	cdnOriginIds := make(map[string]int64)
	for _, v := range req.WebForwardingData.BackendList {
		apiType := protocolHttp
		// 如果条件满足，则覆盖为 HTTPS
		if v.IsHttps == isHttps {
			apiType = protocolHttps
		}


		id, err := s.wafformatter.AddOrigin(ctx, v1.WebJson{
			ApiType:     apiType,
			BackendList: v.Addr,
			Host:        v.CustomHost,
			Comment:     req.WebForwardingData.Comment,
		})
		if err != nil {
			return 0, err
		}
		cdnOriginIds[v.Addr] = id
	}

	// 添加源站到网站
	for _, v := range cdnOriginIds {
		err = s.cdn.AddServerOrigin(ctx, webId, v)
		if err != nil {
			return 0, err
		}
	}


	// 开启proxy
	if req.WebForwardingData.Proxy {
		err = s.proxy.EditProxy(ctx,webId, v1.ProxyProtocolJSON{
			IsOn: true,
			Version: 1,
		})
		if err != nil {
			return 0, err
		}
	}

	// 开启访问日志
	err = s.EditLog(ctx, webId)
	if err != nil {
		return 0, err
	}

	// 开启CC
	if req.WebForwardingData.CcConfig.IsOn {
		err = s.cc.EditCcConfig(ctx, webId, req.WebForwardingData.CcConfig)
		if err != nil {
			return 0, err
		}
	}


	// 开启waf防火墙
	if err = s.ccIpList.AddCcIpListPolicy(ctx, webId, int64(require.GroupId)); err != nil {
		return 0, err
	}



	webModel := s.buildWebForwardingModel(&req.WebForwardingData, int(webId), require)

	id, err := s.webForwardingRepository.AddWebForwarding(ctx, webModel)
	if err != nil {
		return 0, err
	}
	webRuleModel := s.buildWebRuleModel(&req.WebForwardingData, require, id, cdnOriginIds)
	if _, err = s.webForwardingRepository.AddWebForwardingIps(ctx, *webRuleModel); err != nil {
		return 0, err
	}

	if req.WebForwardingData.Domain != "" {
		// 异步任务：将域名添加到白名单
		doMain, err := s.wafformatter.ConvertToWildcardDomain(ctx, req.WebForwardingData.Domain)
		if err != nil {
			return 0, err
		}
		if len(require.GatewayIps) == 0 {
			return 0, fmt.Errorf("网关组不存在")
		}
		firstIp, err := s.gatewayIp.GetGatewayipByHostIdFirst(ctx, int64(require.HostId), int64(require.Uid))
		if err != nil {
			return 0, err
		}
		go s.wafformatter.PublishDomainWhitelistTask(doMain, firstIp, "add")

	}

	// 源站IP过白
	var ips []string
	if req.WebForwardingData.BackendList != nil {
		for _, v := range req.WebForwardingData.BackendList {
			ip, _, err := net.SplitHostPort(v.Addr)
			if err != nil {
				return 0, err
			}
			ips = append(ips, ip)
		}
		go s.wafformatter.PublishIpWhitelistTask(ips, "add", "", "white")
	}

	return id, nil
}

func (s *webForwardingService) EditWebForwarding(ctx context.Context, req *v1.WebForwardingRequest) error {


	err := s.wafformatter.validateWafDomainCount(ctx, v1.GlobalRequire{
		HostId: req.HostId,
		Domain: req.WebForwardingData.Domain,
		Comment: req.WebForwardingData.Comment,
		Uid: req.Uid,
	})
	if err != nil {
		return err
	}

	oldData, err := s.webForwardingRepository.GetWebForwarding(ctx, int64(req.WebForwardingData.Id))
	if err != nil {
		return err
	}
	req.WebForwardingData.SslCertId = int64(oldData.SslCertId)
	req.WebForwardingData.SslPolicyId = int64(oldData.SslPolicyId)
	require, formData, err := s.prepareWafData(ctx, req)
	if err != nil {
		return err
	}

	// 验证端口重复
	var protocol string
	if req.WebForwardingData.IsHttps == isHttps {
		protocol = "https"
	}else{
		protocol = "http"
	}
	err = s.wafformatter.VerifyPort(ctx, protocol, int64(req.WebForwardingData.Id), req.WebForwardingData.Port, int64(require.HostId), req.WebForwardingData.Domain)
	if err != nil {
		return err
	}



	//修改网站端口
	if oldData.Port != req.WebForwardingData.Port || oldData.IsHttps != req.WebForwardingData.IsHttps || oldData.HttpsCert != req.WebForwardingData.HttpsCert || oldData.HttpsKey != req.WebForwardingData.HttpsKey {
		var apiType string
		var closeType string

		// 修改证书
		if oldData.HttpsCert != req.WebForwardingData.HttpsCert || oldData.HttpsKey != req.WebForwardingData.HttpsKey {
			err = s.sslCert.EditSSLCert(ctx, v1.SSL{
				Name:        req.WebForwardingData.Domain,
				CertId:      oldData.SslCertId,
				CertData:    req.WebForwardingData.HttpsCert,
				KeyData:     req.WebForwardingData.HttpsKey,
				CdnUserId:   require.CdnUid,
				Domain:      req.WebForwardingData.Domain,
				Description: req.WebForwardingData.Comment,
			})
			if err != nil {
				return err
			}
		}

		// 切换协议
		var typeConfig v1.TypeJSON
		var closeConfig v1.TypeJSON
		if req.WebForwardingData.IsHttps == isHttps {
			typeConfig = formData.HttpsJSON
			closeConfig = formData.HttpJSON
			apiType = protocolHttps
			closeType = protocolHttp
		} else {
			typeConfig = formData.HttpJSON
			closeConfig = formData.HttpsJSON
			apiType = protocolHttp
			closeType = protocolHttps
		}



		typeJson,err := json.Marshal(typeConfig)
		if err != nil {
			return err
		}
		closeJson,err := json.Marshal(closeConfig)
		if err != nil {
			return err
		}
		// 切换协议
		err = s.cdn.EditServerType(ctx, v1.EditWebsite{
			Id:       int64(oldData.CdnWebId),
			TypeJSON: typeJson,
		}, apiType)
		if err != nil {
			return err
		}
		err = s.cdn.EditServerType(ctx, v1.EditWebsite{
			Id:       int64(oldData.CdnWebId),
			TypeJSON: closeJson,
		}, closeType)
		if err != nil {
			return err
		}
	}

	//修改网站域名
	if oldData.Domain != req.WebForwardingData.Domain {
		type serverName struct {
			Name string `json:"name" form:"name"`
			Type string `json:"type" form:"type"`
		}
		var serverData []serverName
		var serverJson []byte
		serverData = append(serverData, serverName{
			Name: req.WebForwardingData.Domain,
			Type: "full",
		})
		serverJson, err = json.Marshal(serverData)
		if err != nil {
			return err
		}
		err = s.cdn.EditServerName(ctx, v1.EditServerNames{
			ServerId:        int64(oldData.CdnWebId),
			ServerNamesJSON: serverJson,
		})
		if err != nil {
			return err
		}
	}

	//修改网站名字
	if oldData.Comment != req.WebForwardingData.Comment {
		nodeId,err := s.globalLimitRep.GetNodeId(ctx, oldData.CdnWebId)
		if err != nil {
			return err
		}
		err = s.cdn.EditServerBasic(ctx, int64(oldData.CdnWebId), require.Tag,nodeId)
		if err != nil {
			return err
		}
	}

	//修改Proxy
	if oldData.Proxy != req.WebForwardingData.Proxy {
		err = s.proxy.EditProxy(ctx, int64(oldData.CdnWebId), v1.ProxyProtocolJSON{
			IsOn:    req.WebForwardingData.Proxy,
			Version: 1,
		})
		if err != nil {
			return err
		}
	}

	// 修改CC配置
	err = s.cc.EditCcConfig(ctx, int64(oldData.CdnWebId), v1.CcConfigRequest{
		IsOn:            req.WebForwardingData.CcConfig.IsOn,
		Level:           req.WebForwardingData.CcConfig.Level,
		Limit5s:         req.WebForwardingData.CcConfig.Limit5s,
		Limit60s:        req.WebForwardingData.CcConfig.Limit60s,
		Limit300s:       req.WebForwardingData.CcConfig.Limit300s,
		ThresholdMethod: req.WebForwardingData.CcConfig.ThresholdMethod,
	})
	if err != nil {
		return err
	}

	// 将域名添加到白名单
	webData, err := s.webForwardingRepository.GetWebForwarding(ctx, int64(req.WebForwardingData.Id))
	if err != nil {
		return err
	}

	// 异步任务：将域名添加到白名单
	if webData.Domain != req.WebForwardingData.Domain {
		firstIp, err := s.gatewayIp.GetGatewayipByHostIdFirst(ctx, int64(req.HostId), int64(req.Uid))
		if err != nil {
			return err
		}
		doMain, err := s.wafformatter.ConvertToWildcardDomain(ctx, req.WebForwardingData.Domain)
		if err != nil {
			return err
		}

		oldDomain, err := s.wafformatter.ConvertToWildcardDomain(ctx, webData.Domain)
		if err != nil {
			return err
		}
		if len(require.GatewayIps) == 0 {
			return fmt.Errorf("网关组不存在")
		}

		// 查找域名数量,如果数量小于2，删除旧域名
		count, err := s.webForwardingRepository.GetDomainCount(ctx, req.HostId, webData.Domain)
		if err != nil {
			return err
		}
		if count < 2 {
			go s.wafformatter.PublishDomainWhitelistTask(oldDomain, firstIp, "del")
		}
		go s.wafformatter.PublishDomainWhitelistTask(doMain, firstIp, "add")
	}

	// IP过白
	ipData, err := s.webForwardingRepository.GetWebForwardingIpsByID(ctx, req.WebForwardingData.Id)
	if err != nil {
		return err
	}
	var oldIps []string
	var newIps []string
	for _, v := range ipData.BackendList {
		ip, _, err := net.SplitHostPort(v.Addr)
		if err != nil {
			return err
		}
		oldIps = append(oldIps, ip)
	}
	for _, v := range req.WebForwardingData.BackendList {
		ip, _, err := net.SplitHostPort(v.Addr)
		if err != nil {
			return err
		}
		newIps = append(newIps, ip)
	}
	addedIps, removedIps := s.wafformatter.findIpDifferences(oldIps, newIps)
	if len(addedIps) > 0 {
		go s.wafformatter.PublishIpWhitelistTask(addedIps, "add", "", "white")
	}

	// IP过白
	if len(removedIps) > 0 {
		// 1. 一次性获取所有相关IP的数量
		ipsToDelist, err := s.wafformatter.WashDelIps(ctx, removedIps)
		if err != nil {
			return err
		}

		// 4. 如果有需要处理的IP，则批量发布一次任务
		if len(ipsToDelist) > 0 {
			go s.wafformatter.PublishIpWhitelistTask(ipsToDelist, "del", "0", "white")
		}
	}

	//修改源站
	addOrigins, delOrigins := s.FindDifferenceList(ipData.BackendList, req.WebForwardingData.BackendList)
	addedIds := make(map[string]int64)
	for _, v := range addOrigins {
		var apiType string
		if v.IsHttps == isHttps {
			apiType = protocolHttps
		} else {
			apiType = protocolHttp
		}
		id, err := s.wafformatter.AddOrigin(ctx, v1.WebJson{
			ApiType:     apiType,
			BackendList: v.Addr,
			Host:        v.CustomHost,
			Comment:     req.WebForwardingData.Comment,
		})
		if err != nil {
			return err
		}
		addedIds[v.Addr] = id
	}
	for _, v := range addedIds {
		err = s.cdn.AddServerOrigin(ctx, int64(oldData.CdnWebId), v)
		if err != nil {
			return err
		}
	}

	for k, v := range ipData.CdnOriginIds {
		for _, ip := range delOrigins {
			if k == ip.Addr {
				err = s.cdn.DelServerOrigin(ctx, int64(oldData.CdnWebId), v)
				if err != nil {
					return err
				}
				delete(ipData.CdnOriginIds, k)
			}
		}
	}

	maps.Copy(ipData.CdnOriginIds, addedIds)

	webModel := s.buildWebForwardingModel(&req.WebForwardingData, req.WebForwardingData.CdnWebId, require)
	webModel.Id = req.WebForwardingData.Id
	if err = s.webForwardingRepository.EditWebForwarding(ctx, webModel); err != nil {
		return err
	}
	webRuleModel := s.buildWebRuleModel(&req.WebForwardingData, require, req.WebForwardingData.Id, ipData.CdnOriginIds)
	if err = s.webForwardingRepository.EditWebForwardingIps(ctx, *webRuleModel); err != nil {
		return err
	}
	return nil
}

func (s *webForwardingService) DeleteWebForwarding(ctx context.Context, req v1.DeleteWebForwardingRequest) error {
	for _, Id := range req.Ids {
		oldData, err := s.webForwardingRepository.GetWebForwarding(ctx, int64(Id))
		if err != nil {
			return err
		}

		if oldData.HostId != req.HostId {
			return fmt.Errorf("用户权限不足")
		}

		err = s.cdn.DelServer(ctx, int64(oldData.CdnWebId))
		if err != nil {
			return err
		}

		// 异步任务：将域名添加到白名单
		firstIp, err := s.gatewayIp.GetGatewayipByHostIdFirst(ctx, int64(oldData.HostId), int64(req.Uid))
		if err != nil {
			return err
		}
		if oldData.Domain != "" {

			doMain, err := s.wafformatter.ConvertToWildcardDomain(ctx, oldData.Domain)
			if err != nil {
				return err
			}
			go s.wafformatter.PublishDomainWhitelistTask(doMain, firstIp, "del")
		}
		// IP过白
		ipData, err := s.webForwardingRepository.GetWebForwardingIpsByID(ctx, Id)
		if err != nil {
			return err
		}
		var ips []string
		if ipData != nil && len(ipData.BackendList) > 0 {
			for _, v := range ipData.BackendList {
				ip, _, err := net.SplitHostPort(v.Addr)
				if err != nil {
					return err
				}
				ips = append(ips, ip)
			}
		}
		if len(ips) > 0 {
			ipsToDelist, err := s.wafformatter.WashDelIps(ctx, ips)
			if err != nil {
				return err
			}

			// 4. 如果有需要处理的IP，则批量发布一次任务
			if len(ipsToDelist) > 0 {
				go s.wafformatter.PublishIpWhitelistTask(ipsToDelist, "del", "0", "white")
			}
		}

		// 删除ssl
		if oldData.SslCertId != 0 {
			err = s.cdn.DelSSLCert(ctx, int64(oldData.SslCertId))
			if err != nil {
				return err
			}
			err = s.sslCert.EditSslPolicy(ctx, int64(oldData.SslPolicyId), []int64{int64(oldData.SslCertId)}, "del")
			if err != nil {
				return err
			}
		}




		if err = s.webForwardingRepository.DeleteWebForwarding(ctx, int64(Id)); err != nil {
			return err
		}
		if err = s.webForwardingRepository.DeleteWebForwardingIpsById(ctx, Id); err != nil {
			return err
		}
	}

	return nil
}

func (s *webForwardingService) GetWebForwardingWafWebAllIps(ctx context.Context, req v1.GetForwardingRequest) ([]v1.WebForwardingDataRequest, error) {
	type CombinedResult struct {
		Id          int
		Forwarding  *model.WebForwarding
		BackendRule *model.WebForwardingRule
		Err         error // 如果此ID的处理出错，则携带错误
	}
	g, gCtx := errgroup.WithContext(ctx)
	ids, err := s.webForwardingRepository.GetWebForwardingWafWebAllIds(gCtx, req.HostId)
	if err != nil {
		return nil, fmt.Errorf("GetWebForwardingWafWebAllIds failed: %w", err)
	}

	if len(ids) == 0 {
		return nil, nil // 没有ID，直接返回空切片
	}

	// 创建一个通道来接收每个ID的处理结果
	// 通道缓冲区大小设为ID数量，这样发送者不会因为接收者慢而阻塞（在所有goroutine都启动后）
	resultsChan := make(chan CombinedResult, len(ids))

	for _, idVal := range ids {
		currentID := idVal // 捕获循环变量
		g.Go(func() error {
			var wf *model.WebForwarding
			var bk *model.WebForwardingRule
			var localErr error

			// 1. 获取 WebForwarding 信息
			wf, localErr = s.webForwardingRepository.GetWebForwarding(gCtx, int64(currentID))
			if localErr != nil {
				// 发送错误到通道，并由 errgroup 捕获
				// errgroup 会处理第一个非nil错误，并取消其他 goroutine
				resultsChan <- CombinedResult{Id: currentID, Err: fmt.Errorf("GetWebForwarding for id %d failed: %w", currentID, localErr)}
				return localErr // 返回错误给 errgroup
			}
			if wf == nil { // 正常情况下，如果没错误，wf不应为nil，但防御性检查
				localErr = fmt.Errorf("GetWebForwarding for id %d returned nil data without error", currentID)
				resultsChan <- CombinedResult{Id: currentID, Err: localErr}
				return localErr
			}

			// 2. 获取 Backend IP 信息
			// 注意：这里我们允许 GetWebForwardingIpsByID 可能返回 nil 数据（例如没有规则）而不是错误
			// 如果它也可能返回错误，则处理方式与上面类似
			bk, localErr = s.webForwardingRepository.GetWebForwardingIpsByID(gCtx, currentID)
			if localErr != nil {
				// 如果获取IP信息失败是一个致命错误，则也应返回错误
				// 如果允许部分成功（比如有WebForwarding但没有IP信息），则可以不将此视为errgroup的错误
				// 这里假设它也是一个需要errgroup捕获的错误
				resultsChan <- CombinedResult{Id: currentID, Forwarding: wf, Err: fmt.Errorf("GetWebForwardingIpsByID for id %d failed: %w", currentID, localErr)}
				return localErr // 返回错误给 errgroup
			}
			// bk 可能是 nil 如果没有错误且没有规则，这取决于业务逻辑

			// 发送成功的结果到通道
			resultsChan <- CombinedResult{Id: currentID, Forwarding: wf, BackendRule: bk}
			return nil // 此goroutine成功
		})
	}

	// 等待所有goroutine完成
	groupErr := g.Wait()

	// 关闭通道，表示所有发送者都已完成
	// 这一步很重要，这样下面的 range 循环才能正常结束
	close(resultsChan)

	// 如果 errgroup 捕获到任何错误，优先返回该错误
	if groupErr != nil {
		// 虽然errgroup已经出错了，但通道中可能已经有一些结果（来自出错前成功或出错的goroutine）
		// 我们需要排空通道以避免goroutine泄漏（如果它们在发送时阻塞）
		// 但由于我们优先返回groupErr，这些结果将被丢弃。
		// 在这种设计下，通常任何一个子任务失败都会导致整个操作失败。
		return nil, groupErr
	}

	// 如果没有错误，收集所有成功的结果
	finalResults := make([]v1.WebForwardingDataRequest, 0, len(ids))
	for res := range resultsChan {
		// 再次检查通道中的错误，尽管 errgroup 应该已经捕获了
		// 但这是一种更细致的错误处理，以防万一有goroutine在errgroup.Wait()前发送了错误但未被errgroup捕获
		// （理论上，如果goroutine返回了错误，errgroup会处理）
		// 主要目的是处理 res.forwarding 为 nil 的情况 (如果上面允许不返回错误)
		if res.Err != nil {
			// 如果到这里还有错误，说明逻辑可能有问题，或者我们决定忽略某些类型的子错误
			// 在此示例中，因为 g.Wait() 没有错误，所以这里的 res.err 应该是nil
			// 如果不是，那么可能是goroutine在return nil前发送了带有错误的res。
			// 严格来说，如果errgroup没有错误，这里res.err也应该是nil
			// 但以防万一，我们可以记录日志
			return nil, fmt.Errorf("received error from goroutine for ID %d: %w", res.Id, res.Err)
		}
		if res.Forwarding == nil {
			return nil, fmt.Errorf("received nil forwarding from goroutine for ID %d", res.Id)
		}

		dataReq := v1.WebForwardingDataRequest{
			Id:        res.Forwarding.Id,
			Port:      res.Forwarding.Port,
			Domain:    res.Forwarding.Domain,
			IsHttps:   res.Forwarding.IsHttps,
			Comment:   res.Forwarding.Comment,
			HttpsKey:  res.Forwarding.HttpsKey,
			HttpsCert: res.Forwarding.HttpsCert,
			Proxy:     res.Forwarding.Proxy,
			CcConfig:  v1.CcConfigRequest{
				IsOn:        res.Forwarding.Cc,
				ThresholdMethod: res.Forwarding.ThresholdMethod,
				Level:       res.Forwarding.Level,
				Limit5s:     res.Forwarding.Limit5s,
				Limit60s:    res.Forwarding.Limit60s,
				Limit300s:   res.Forwarding.Limit300s,
			},
		}

		if res.BackendRule != nil { // 只有当 BackendRule 存在时才填充相关字段
			dataReq.BackendList = res.BackendRule.BackendList
		}
		finalResults = append(finalResults, dataReq)
	}

	sort.Slice(finalResults, func(i, j int) bool {
		return finalResults[i].Id > finalResults[j].Id
	})
	return finalResults, nil
}

// 清洗IP
func (s *webForwardingService) WashDifferentIp(newIpList []string, oldIpList []string) (addedDenyIps []string, removedDenyIps []string) {
	var newAllowIps []string
	var oldAllowIps []string
	if len(oldIpList) > 0 {
		for _, v := range oldIpList {
			if net.ParseIP(v) != nil {
				oldAllowIps = append(oldAllowIps, v)
			}
		}
	}
	if len(newIpList) > 0 {
		for _, v := range newIpList {
			if net.ParseIP(v) != nil {
				newAllowIps = append(newAllowIps, v)
			}
		}
	}
	addedDenyIps, removedDenyIps = s.wafformatter.findIpDifferences(oldAllowIps, newAllowIps)
	return addedDenyIps, removedDenyIps
}

// 修改日志配置
func (s *webForwardingService) EditLog(ctx context.Context,webId int64) error {
	webConfigId, err := s.webForwardingRepository.GetWebConfigId(ctx, webId)
	if err != nil {
		return err
	}

	if err := s.cdn.EditWebLog(ctx, webConfigId,v1.WebLog{
		IsPrior: false,
		IsOn:    true,
		Fields:  []int64{1, 2, 6, 7},
		Status1: true,
		Status2: true,
		Status3: true,
		Status4: true,
		Status5: true,
		FirewallOnly: false,
		EnableClientClosed: false,
	}); err != nil {
		return err
	}
	return nil
}




func (s *webForwardingService) BulidFormData(ctx context.Context,formData v1.Website) (v1.WebsiteSend, error) {
	httpJSON, err := json.Marshal(formData.HttpJSON)
	if err != nil {
		return v1.WebsiteSend{},err
	}
	httpsJSON, err := json.Marshal(formData.HttpsJSON)
	if err != nil {
		return v1.WebsiteSend{},err
	}
	formDataSend := v1.WebsiteSend{
		UserId: formData.UserId,
		AdminId:           formData.AdminId,
		Type:             formData.Type,
		Name:             formData.Name,
		Description:      formData.Description,
		ServerNamesJSON:  formData.ServerNamesJSON,
		HttpJSON:         httpJSON,
		HttpsJSON:        httpsJSON,
		TcpJSON:          formData.TcpJSON,
		TlsJSON:          formData.TlsJSON,
		UdpJSON:          formData.UdpJSON,
		WebId:            formData.WebId,
		ReverseProxyJSON: formData.ReverseProxyJSON,
		ServerGroupIds:   formData.ServerGroupIds,
		UserPlanId:       formData.UserPlanId,
		NodeClusterId:    formData.NodeClusterId,
		IncludeNodesJSON: formData.IncludeNodesJSON,
		ExcludeNodesJSON: formData.ExcludeNodesJSON,
	}
	return formDataSend, nil
}