package userclient

import (
	"context"

	userv1 "hyapp.local/api/proto/user/v1"
)

// Country 是 admin-server 暴露给后台前端的国家主数据 DTO。
// 这里不引用 user-service 的 domain/storage 包，避免后台服务和用户服务代码结构耦合。
type Country struct {
	// CountryID 是 user-service 生成的国家主键，后台增删改查都以它定位记录。
	CountryID int64 `json:"countryId"`
	// CountryName 是稳定英文或拼音名称，例如 China、United States。
	CountryName string `json:"countryName"`
	// CountryCode 是 App 和用户链路使用的 canonical 国家码，创建后不可变。
	CountryCode string `json:"countryCode"`
	// CountryDisplayName 是后台和 App 注册页展示用中文名。
	CountryDisplayName string `json:"countryDisplayName"`
	// SortOrder 控制 App 注册页和后台列表的默认排序。
	SortOrder int32 `json:"sortOrder"`
	// CreatedAtMs 直接透传 user-service 的毫秒时间戳，避免跨服务时区转换。
	CreatedAtMs int64 `json:"createdAtMs"`
	// UpdatedAtMs 直接透传 user-service 的毫秒时间戳，便于后台做新旧数据判断。
	UpdatedAtMs int64 `json:"updatedAtMs"`
	// ISOAlpha3 是 ISO 3166-1 alpha-3 或明确的 user-assigned code。
	ISOAlpha3 string `json:"isoAlpha3"`
	// ISONumeric 必须保持字符串，避免 020 这类前导零被破坏。
	ISONumeric string `json:"isoNumeric"`
	// PhoneCountryCode 是 E.164 国家呼叫码，例如 +86。
	PhoneCountryCode string `json:"phoneCountryCode"`
	// Enabled 表示该国家是否允许 App 注册和用户改国家选择。
	Enabled bool `json:"enabled"`
	// Flag 是展示字段，不参与国家唯一性、区域归属或权限判断。
	Flag string `json:"flag"`
}

// Region 是 user-service 区域主数据投影；countries 只包含当前 active 国家码。
type Region struct {
	// RegionID 是区域主键，BD Leader/BD/Agency 后续都围绕它建立组织关系。
	RegionID int64 `json:"regionId"`
	// RegionCode 是稳定业务编码；后台修改时仍由 user-service 做唯一性校验。
	RegionCode string `json:"regionCode"`
	// Name 是后台展示名。
	Name string `json:"name"`
	// Status 当前只由 user-service 约束为 active 或 disabled。
	Status string `json:"status"`
	// Countries 是 active 映射国家码列表；一个国家不能同时属于多个 active 区域。
	Countries []string `json:"countries"`
	// SortOrder 控制后台和业务选择器排序。
	SortOrder int32 `json:"sortOrder"`
	// CreatedAtMs 直接透传 user-service 的毫秒时间戳。
	CreatedAtMs int64 `json:"createdAtMs"`
	// UpdatedAtMs 直接透传 user-service 的毫秒时间戳。
	UpdatedAtMs int64 `json:"updatedAtMs"`
}

// ListCountriesRequest 支持 enabled 三态过滤：nil 表示全部，true/false 表示显式筛选。
type ListCountriesRequest struct {
	RequestID string
	Caller    string
	Enabled   *bool
}

// UpdateCountryRequest 只允许修改展示和辅助字段，不允许修改 country_code。
type UpdateCountryRequest struct {
	RequestID          string
	Caller             string
	CountryID          int64
	CountryName        string
	CountryDisplayName string
	SortOrder          int32
	OperatorUserID     int64
	ISOAlpha3          string
	ISONumeric         string
	PhoneCountryCode   string
	Flag               string
}

// ListRegionsRequest 支持 status 过滤；空字符串表示全部。
type ListRegionsRequest struct {
	RequestID string
	Caller    string
	Status    string
}

// GetRegionRequest 按区域主键查询单个区域及 active 国家码。
type GetRegionRequest struct {
	RequestID string
	Caller    string
	RegionID  int64
}

// UpdateRegionRequest 只修改区域展示字段，不替换国家归属。
type UpdateRegionRequest struct {
	RequestID      string
	Caller         string
	RegionID       int64
	RegionCode     string
	Name           string
	SortOrder      int32
	OperatorUserID int64
}

// ReplaceRegionCountriesRequest 原子替换区域国家归属，并由 user-service 创建用户区域重算任务。
type ReplaceRegionCountriesRequest struct {
	RequestID      string
	Caller         string
	RegionID       int64
	Countries      []string
	OperatorUserID int64
}

func (c *GRPCClient) ListCountries(ctx context.Context, req ListCountriesRequest) ([]*Country, error) {
	resp, err := c.countryClient.ListCountries(ctx, &userv1.ListCountriesRequest{
		Meta:    requestMeta(ctx, req.RequestID, req.Caller),
		Enabled: req.Enabled,
	})
	if err != nil {
		return nil, err
	}
	items := make([]*Country, 0, len(resp.GetCountries()))
	for _, country := range resp.GetCountries() {
		items = append(items, fromProtoCountry(country))
	}
	return items, nil
}

func (c *GRPCClient) UpdateCountry(ctx context.Context, req UpdateCountryRequest) (*Country, error) {
	resp, err := c.countryClient.UpdateCountry(ctx, &userv1.UpdateCountryRequest{
		Meta:               requestMeta(ctx, req.RequestID, req.Caller),
		CountryId:          req.CountryID,
		CountryName:        req.CountryName,
		CountryDisplayName: req.CountryDisplayName,
		SortOrder:          req.SortOrder,
		OperatorUserId:     req.OperatorUserID,
		IsoAlpha3:          req.ISOAlpha3,
		IsoNumeric:         req.ISONumeric,
		PhoneCountryCode:   req.PhoneCountryCode,
		Flag:               req.Flag,
	})
	if err != nil {
		return nil, err
	}
	return fromProtoCountry(resp.GetCountry()), nil
}

func (c *GRPCClient) ListRegions(ctx context.Context, req ListRegionsRequest) ([]*Region, error) {
	resp, err := c.regionClient.ListRegions(ctx, &userv1.ListRegionsRequest{
		Meta:   requestMeta(ctx, req.RequestID, req.Caller),
		Status: req.Status,
	})
	if err != nil {
		return nil, err
	}
	items := make([]*Region, 0, len(resp.GetRegions()))
	for _, region := range resp.GetRegions() {
		items = append(items, fromProtoRegion(region))
	}
	return items, nil
}

func (c *GRPCClient) GetRegion(ctx context.Context, req GetRegionRequest) (*Region, error) {
	resp, err := c.regionClient.GetRegion(ctx, &userv1.GetRegionRequest{
		Meta:     requestMeta(ctx, req.RequestID, req.Caller),
		RegionId: req.RegionID,
	})
	if err != nil {
		return nil, err
	}
	return fromProtoRegion(resp.GetRegion()), nil
}

func (c *GRPCClient) UpdateRegion(ctx context.Context, req UpdateRegionRequest) (*Region, error) {
	resp, err := c.regionClient.UpdateRegion(ctx, &userv1.UpdateRegionRequest{
		Meta:           requestMeta(ctx, req.RequestID, req.Caller),
		RegionId:       req.RegionID,
		RegionCode:     req.RegionCode,
		Name:           req.Name,
		SortOrder:      req.SortOrder,
		OperatorUserId: req.OperatorUserID,
	})
	if err != nil {
		return nil, err
	}
	return fromProtoRegion(resp.GetRegion()), nil
}

func (c *GRPCClient) ReplaceRegionCountries(ctx context.Context, req ReplaceRegionCountriesRequest) (*Region, error) {
	resp, err := c.regionClient.ReplaceRegionCountries(ctx, &userv1.ReplaceRegionCountriesRequest{
		Meta:           requestMeta(ctx, req.RequestID, req.Caller),
		RegionId:       req.RegionID,
		Countries:      append([]string(nil), req.Countries...),
		OperatorUserId: req.OperatorUserID,
	})
	if err != nil {
		return nil, err
	}
	return fromProtoRegion(resp.GetRegion()), nil
}

func fromProtoCountry(country *userv1.Country) *Country {
	if country == nil {
		return nil
	}
	return &Country{
		CountryID:          country.GetCountryId(),
		CountryName:        country.GetCountryName(),
		CountryCode:        country.GetCountryCode(),
		CountryDisplayName: country.GetCountryDisplayName(),
		SortOrder:          country.GetSortOrder(),
		CreatedAtMs:        country.GetCreatedAtMs(),
		UpdatedAtMs:        country.GetUpdatedAtMs(),
		ISOAlpha3:          country.GetIsoAlpha3(),
		ISONumeric:         country.GetIsoNumeric(),
		PhoneCountryCode:   country.GetPhoneCountryCode(),
		Enabled:            country.GetEnabled(),
		Flag:               country.GetFlag(),
	}
}

func fromProtoRegion(region *userv1.Region) *Region {
	if region == nil {
		return nil
	}
	return &Region{
		RegionID:    region.GetRegionId(),
		RegionCode:  region.GetRegionCode(),
		Name:        region.GetName(),
		Status:      region.GetStatus(),
		Countries:   append([]string{}, region.GetCountries()...),
		SortOrder:   region.GetSortOrder(),
		CreatedAtMs: region.GetCreatedAtMs(),
		UpdatedAtMs: region.GetUpdatedAtMs(),
	}
}
