package payment

import (
	"context"
	"errors"
	"fmt"
	"sort"
	"strconv"
	"strings"
	"time"

	"hyapp-admin-server/internal/appctx"
	"hyapp-admin-server/internal/middleware"
	"hyapp-admin-server/internal/model"
	"hyapp-admin-server/internal/modules/shared"
	"hyapp-admin-server/internal/repository"
	"hyapp-admin-server/internal/response"
	walletv1 "hyapp.local/api/proto/wallet/v1"

	"github.com/gin-gonic/gin"
)

const (
	financeViewPermission                = "finance:view"
	legacyMoneyViewPermission            = "money:view"
	temporaryPaymentLinkCreatePermission = "payment-temporary-link:create"
	temporaryRechargeAudience            = "temporary"
)

type temporaryPaymentLinkCreateRequest struct {
	AppCode         string `json:"appCode"`
	RegionID        int64  `json:"regionId"`
	USDMinorAmount  int64  `json:"usdMinorAmount"`
	ProviderCode    string `json:"providerCode"`
	PaymentMethodID int64  `json:"paymentMethodId"`
	ReturnURL       string `json:"returnUrl"`
	Language        string `json:"language"`
}

type moneyScopeItemDTO struct {
	AppCode  string `json:"appCode"`
	RegionID int64  `json:"regionId"`
}

type moneyAppDTO struct {
	AppID       int64  `json:"appId"`
	AppCode     string `json:"appCode"`
	AppName     string `json:"appName"`
	LogoURL     string `json:"logoUrl"`
	PackageName string `json:"packageName"`
	Platform    string `json:"platform"`
	Status      string `json:"status"`
}

type moneyRegionDTO struct {
	AppCode    string   `json:"appCode"`
	RegionID   int64    `json:"regionId"`
	RegionCode string   `json:"regionCode"`
	Name       string   `json:"name"`
	Status     string   `json:"status"`
	SortOrder  int      `json:"sortOrder"`
	Countries  []string `json:"countries"`
}

type moneyCountryDTO struct {
	AppCode            string `json:"appCode"`
	CountryID          int64  `json:"countryId"`
	CountryCode        string `json:"countryCode"`
	CountryName        string `json:"countryName"`
	CountryDisplayName string `json:"countryDisplayName"`
	Flag               string `json:"flag"`
	Enabled            bool   `json:"enabled"`
	RegionID           int64  `json:"regionId"`
	SortOrder          int    `json:"sortOrder"`
}

type moneyPerformanceItemDTO struct {
	AppCode         string `json:"appCode"`
	RegionID        int64  `json:"regionId"`
	OperatorUserID  uint   `json:"operatorUserId"`
	OperatorName    string `json:"operatorName"`
	OperatorAccount string `json:"operatorAccount"`
	PaidLinkCount   int64  `json:"paidLinkCount"`
	PaidUSDMinor    int64  `json:"paidUsdMinor"`
	LastPaidAtMS    int64  `json:"lastPaidAtMs"`
}

type paidTemporaryOrder struct {
	AppCode         string
	OrderID         string
	USDMinorAmount  int64
	Status          string
	CountryCode     string
	ProviderCode    string
	PaymentMethodID int64
	PayURL          string
	CreatedAtMS     int64
	UpdatedAtMS     int64
}

func (h *Handler) GetMoneyScope(c *gin.Context) {
	access, ok := h.moneyAccess(c)
	if !ok {
		return
	}
	if h.userDB == nil {
		response.ServerError(c, "user mysql is not configured")
		return
	}
	apps, regions, countries, err := h.loadMoneyMasterData(c.Request.Context(), access)
	if err != nil {
		response.ServerError(c, "获取财务范围失败")
		return
	}
	response.OK(c, gin.H{
		"all":       access.All,
		"scopes":    moneyScopeDTOsFromModel(access.Scopes),
		"apps":      apps,
		"regions":   regions,
		"countries": countries,
	})
}

func (h *Handler) GetMoneyPerformance(c *gin.Context) {
	access, ok := h.moneyAccess(c)
	if !ok {
		return
	}
	if h.walletDB == nil || h.store == nil {
		response.OK(c, gin.H{"items": []moneyPerformanceItemDTO{}, "summary": moneyPerformanceSummary(nil)})
		return
	}
	appCodes, err := h.performanceAppCodes(c.Request.Context(), access, firstQuery(c, "app_code", "appCode"))
	if err != nil {
		response.ServerError(c, "获取绩效 App 失败")
		return
	}
	regionID := queryInt64(c, "region_id", "regionId")
	operatorUserID := queryUint(c, "operator_user_id", "operatorUserId")
	startAtMS := queryInt64(c, "start_at_ms", "startAtMs")
	endAtMS := queryInt64(c, "end_at_ms", "endAtMs")

	aggregates := map[string]*moneyPerformanceItemDTO{}
	userIDs := []uint{}
	for _, appCode := range appCodes {
		orders, err := h.listPaidTemporaryOrders(c.Request.Context(), appCode, startAtMS, endAtMS)
		if err != nil {
			response.ServerError(c, "获取支付绩效失败")
			return
		}
		orderIDs := make([]string, 0, len(orders))
		for _, order := range orders {
			orderIDs = append(orderIDs, order.OrderID)
		}
		owners, err := h.store.TemporaryPaymentLinkOwners(appCode, orderIDs)
		if err != nil {
			response.ServerError(c, "获取支付链接归属失败")
			return
		}
		for _, order := range orders {
			owner, ok := owners[order.OrderID]
			if !ok || !access.All && !access.Allows(owner.AppCode, owner.RegionID) {
				continue
			}
			if regionID > 0 && owner.RegionID != regionID {
				continue
			}
			if operatorUserID > 0 && owner.AdminUserID != operatorUserID {
				continue
			}
			key := fmt.Sprintf("%s:%d:%d", owner.AppCode, owner.RegionID, owner.AdminUserID)
			item := aggregates[key]
			if item == nil {
				item = &moneyPerformanceItemDTO{
					AppCode:        owner.AppCode,
					RegionID:       owner.RegionID,
					OperatorUserID: owner.AdminUserID,
				}
				aggregates[key] = item
				userIDs = append(userIDs, owner.AdminUserID)
			}
			item.PaidLinkCount++
			item.PaidUSDMinor += order.USDMinorAmount
			if order.UpdatedAtMS > item.LastPaidAtMS {
				item.LastPaidAtMS = order.UpdatedAtMS
			}
		}
	}

	users, err := h.store.FindUsersByIDs(userIDs)
	if err != nil {
		response.ServerError(c, "获取运营用户失败")
		return
	}
	items := make([]moneyPerformanceItemDTO, 0, len(aggregates))
	for _, item := range aggregates {
		if user, ok := users[item.OperatorUserID]; ok {
			item.OperatorName = user.Name
			item.OperatorAccount = user.Username
		}
		items = append(items, *item)
	}
	sort.Slice(items, func(i, j int) bool {
		if items[i].PaidUSDMinor == items[j].PaidUSDMinor {
			return items[i].LastPaidAtMS > items[j].LastPaidAtMS
		}
		return items[i].PaidUSDMinor > items[j].PaidUSDMinor
	})
	response.OK(c, gin.H{"items": items, "summary": moneyPerformanceSummary(items)})
}

func (h *Handler) CreateTemporaryPaymentLink(c *gin.Context) {
	if h.store == nil {
		response.ServerError(c, "admin store is not configured")
		return
	}
	var request temporaryPaymentLinkCreateRequest
	if err := c.ShouldBindJSON(&request); err != nil {
		response.BadRequest(c, "支付链接参数不正确")
		return
	}
	appCode := appctx.Normalize(request.AppCode)
	if appCode == "" || request.RegionID <= 0 || request.USDMinorAmount <= 0 || request.PaymentMethodID <= 0 {
		response.BadRequest(c, "支付链接参数不完整")
		return
	}
	access, ok := h.moneyAccess(c)
	if !ok {
		return
	}
	if !access.Allows(appCode, request.RegionID) {
		response.Forbidden(c, "没有该 App 区域的财务范围")
		return
	}
	method, err := h.findTemporaryPaymentMethod(c.Request.Context(), appCode, request.ProviderCode, request.PaymentMethodID)
	if err != nil {
		if errors.Is(err, errTemporaryPaymentMethodInvalid) {
			response.BadRequest(c, "支付方式不正确")
			return
		}
		writeWalletError(c, err, "获取支付方式失败")
		return
	}
	if ok, err := h.countryBelongsToRegion(c.Request.Context(), appCode, request.RegionID, method.GetCountryCode()); err != nil {
		response.ServerError(c, "校验区域国家失败")
		return
	} else if !ok {
		response.BadRequest(c, "支付方式国家不属于所选区域")
		return
	}
	language := strings.TrimSpace(request.Language)
	if language == "" {
		language = "en"
	}
	resp, err := h.wallet.CreateTemporaryRechargeOrder(c.Request.Context(), &walletv1.CreateTemporaryRechargeOrderRequest{
		RequestId:       middleware.CurrentRequestID(c),
		AppCode:         appCode,
		CommandId:       temporaryPaymentCommandID(shared.ActorFromContext(c).UserID, middleware.CurrentRequestID(c)),
		CoinAmount:      0,
		UsdMinorAmount:  request.USDMinorAmount,
		ProviderCode:    method.GetProviderCode(),
		PaymentMethodId: method.GetMethodId(),
		ReturnUrl:       strings.TrimSpace(request.ReturnURL),
		ClientIp:        c.ClientIP(),
		Language:        language,
		PayerName:       shared.ActorFromContext(c).Username,
		PayerAccount:    shared.ActorFromContext(c).Username,
	})
	if err != nil {
		writeWalletError(c, err, "创建支付链接失败")
		return
	}
	order := resp.GetOrder()
	if order == nil || strings.TrimSpace(order.GetOrderId()) == "" {
		response.ServerError(c, "创建支付链接失败")
		return
	}
	if err := h.store.RecordTemporaryPaymentLinkOwner(model.TemporaryPaymentLinkOwner{
		AppCode:     appCode,
		OrderID:     order.GetOrderId(),
		AdminUserID: shared.ActorFromContext(c).UserID,
		RegionID:    request.RegionID,
	}); err != nil {
		response.ServerError(c, "记录支付链接归属失败")
		return
	}
	item := temporaryPaymentLinkFromProto(order)
	items, err := h.enrichAndFilterTemporaryLinks(appCode, []temporaryPaymentLinkDTO{item}, access, 0, 0)
	if err != nil {
		response.ServerError(c, "获取支付链接归属失败")
		return
	}
	if len(items) > 0 {
		item = items[0]
	}
	shared.OperationLogWithResourceID(c, h.audit, "create-temporary-payment-link", "external_recharge_orders", order.GetOrderId(), "success", fmt.Sprintf("%s:%d", appCode, request.RegionID))
	response.Created(c, item)
}

func (h *Handler) moneyAccess(c *gin.Context) (repository.MoneyAccess, bool) {
	if h.store == nil {
		return repository.MoneyAccess{All: true}, true
	}
	access, err := h.store.MoneyAccessForUser(shared.ActorFromContext(c).UserID)
	if err != nil {
		response.ServerError(c, "获取财务范围失败")
		return repository.MoneyAccess{}, false
	}
	return access, true
}

func moneyAccessAllowsApp(access repository.MoneyAccess, appCode string) bool {
	if access.All {
		return true
	}
	appCode = appctx.Normalize(appCode)
	for _, scope := range access.Scopes {
		if appctx.Normalize(scope.AppCode) == appCode {
			return true
		}
	}
	return false
}

func (h *Handler) enrichAndFilterTemporaryLinks(appCode string, items []temporaryPaymentLinkDTO, access repository.MoneyAccess, regionID int64, operatorUserID uint) ([]temporaryPaymentLinkDTO, error) {
	orderIDs := make([]string, 0, len(items))
	for _, item := range items {
		orderIDs = append(orderIDs, item.OrderID)
	}
	owners, err := h.store.TemporaryPaymentLinkOwners(appCode, orderIDs)
	if err != nil {
		return nil, err
	}
	userIDs := []uint{}
	for _, owner := range owners {
		userIDs = append(userIDs, owner.AdminUserID)
	}
	users, err := h.store.FindUsersByIDs(userIDs)
	if err != nil {
		return nil, err
	}
	out := make([]temporaryPaymentLinkDTO, 0, len(items))
	for _, item := range items {
		owner, ok := owners[item.OrderID]
		if !ok {
			if access.All && regionID == 0 && operatorUserID == 0 {
				out = append(out, item)
			}
			continue
		}
		if !access.All && !access.Allows(owner.AppCode, owner.RegionID) {
			continue
		}
		if regionID > 0 && owner.RegionID != regionID {
			continue
		}
		if operatorUserID > 0 && owner.AdminUserID != operatorUserID {
			continue
		}
		item.RegionID = owner.RegionID
		item.OwnerUserID = owner.AdminUserID
		if user, ok := users[owner.AdminUserID]; ok {
			item.OwnerUsername = user.Username
			item.OwnerName = user.Name
		}
		out = append(out, item)
	}
	return out, nil
}

var errTemporaryPaymentMethodInvalid = errors.New("temporary payment method invalid")

func (h *Handler) findTemporaryPaymentMethod(ctx context.Context, appCode string, providerCode string, paymentMethodID int64) (*walletv1.ThirdPartyPaymentMethod, error) {
	resp, err := h.wallet.ListThirdPartyPaymentChannels(ctx, &walletv1.ListThirdPartyPaymentChannelsRequest{
		RequestId:              strconv.FormatInt(time.Now().UnixNano(), 10),
		AppCode:                appCode,
		ProviderCode:           strings.TrimSpace(providerCode),
		Status:                 "active",
		IncludeDisabledMethods: true,
	})
	if err != nil {
		return nil, err
	}
	for _, channel := range resp.GetChannels() {
		for _, method := range channel.GetMethods() {
			if method.GetMethodId() != paymentMethodID {
				continue
			}
			if strings.TrimSpace(providerCode) != "" && method.GetProviderCode() != strings.TrimSpace(providerCode) {
				return nil, errTemporaryPaymentMethodInvalid
			}
			if method.GetStatus() != "active" || strings.TrimSpace(method.GetCountryCode()) == "" {
				return nil, errTemporaryPaymentMethodInvalid
			}
			return method, nil
		}
	}
	return nil, errTemporaryPaymentMethodInvalid
}

func (h *Handler) countryBelongsToRegion(ctx context.Context, appCode string, regionID int64, countryCode string) (bool, error) {
	appCode = appctx.Normalize(appCode)
	countryCode = strings.ToUpper(strings.TrimSpace(countryCode))
	if countryCode == "" || countryCode == "GLOBAL" {
		return false, nil
	}
	for _, source := range h.moneyRegionSources {
		// legacy App 的区域-国家关系和区域目录同源；source 明确命中时直接返回，避免 Yumi/Aslan 回落到 hyapp_user 本地表。
		ok, handled, err := source.CountryBelongsToRegion(ctx, appCode, regionID, countryCode)
		if err != nil {
			return false, err
		}
		if handled {
			return ok, nil
		}
	}
	if h.userDB == nil {
		return false, errors.New("user mysql is not configured")
	}
	var count int
	err := h.userDB.QueryRowContext(ctx, `
		SELECT COUNT(*)
		FROM region_countries
		WHERE app_code = ? AND region_id = ? AND country_code = ? AND status = 'active'
	`, appCode, regionID, countryCode).Scan(&count)
	return count > 0, err
}

func (h *Handler) loadMoneyMasterData(ctx context.Context, access repository.MoneyAccess) ([]moneyAppDTO, []moneyRegionDTO, []moneyCountryDTO, error) {
	apps, err := h.listMoneyApps(ctx, access)
	if err != nil {
		return nil, nil, nil, err
	}
	appCodes := make([]string, 0, len(apps))
	for _, app := range apps {
		appCodes = append(appCodes, app.AppCode)
	}
	regions, err := h.listMoneyRegions(ctx, access, appCodes)
	if err != nil {
		return nil, nil, nil, err
	}
	countries, err := h.listMoneyCountries(ctx, access, appCodes)
	if err != nil {
		return nil, nil, nil, err
	}
	// Yumi/Aslan 这类 legacy App 的区域事实来自线上 likei Mongo；这里合并目录数据，但财务授权仍只保存 app_code + region_id。
	sourceApps, sourceRegions, sourceCountries, err := h.listMoneyRegionSources(ctx, access)
	if err != nil {
		return nil, nil, nil, err
	}
	apps = appendUniqueMoneyApps(apps, sourceApps)
	regions = appendUniqueMoneyRegions(regions, sourceRegions)
	countries = appendUniqueMoneyCountries(countries, sourceCountries)
	return apps, regions, countries, nil
}

func (h *Handler) listMoneyApps(ctx context.Context, access repository.MoneyAccess) ([]moneyAppDTO, error) {
	where, args := scopedAppWhere(access)
	rows, err := h.userDB.QueryContext(ctx, `
		SELECT app_id, app_code, app_name, logo_url, package_name, platform, status
		FROM apps
		WHERE status = 'active'`+where+`
		ORDER BY app_name ASC, app_code ASC`, args...)
	if err != nil {
		return nil, err
	}
	defer rows.Close()
	items := []moneyAppDTO{}
	for rows.Next() {
		var item moneyAppDTO
		if err := rows.Scan(&item.AppID, &item.AppCode, &item.AppName, &item.LogoURL, &item.PackageName, &item.Platform, &item.Status); err != nil {
			return nil, err
		}
		items = append(items, item)
	}
	return items, rows.Err()
}

func (h *Handler) listMoneyRegions(ctx context.Context, access repository.MoneyAccess, appCodes []string) ([]moneyRegionDTO, error) {
	if len(appCodes) == 0 {
		return []moneyRegionDTO{}, nil
	}
	where, args := inClause("r.app_code", appCodes)
	rows, err := h.userDB.QueryContext(ctx, `
		SELECT r.app_code, r.region_id, r.region_code, r.name, r.status, r.sort_order,
		       COALESCE(GROUP_CONCAT(rc.country_code ORDER BY rc.country_code SEPARATOR ','), '')
		FROM regions r
		LEFT JOIN region_countries rc
		  ON rc.app_code = r.app_code AND rc.region_id = r.region_id AND rc.status = 'active'
		WHERE r.status = 'active' AND `+where+`
		GROUP BY r.app_code, r.region_id, r.region_code, r.name, r.status, r.sort_order
		ORDER BY r.app_code ASC, r.sort_order DESC, r.name ASC`, args...)
	if err != nil {
		return nil, err
	}
	defer rows.Close()
	items := []moneyRegionDTO{}
	for rows.Next() {
		var item moneyRegionDTO
		var countries string
		if err := rows.Scan(&item.AppCode, &item.RegionID, &item.RegionCode, &item.Name, &item.Status, &item.SortOrder, &countries); err != nil {
			return nil, err
		}
		if !access.All && !access.Allows(item.AppCode, item.RegionID) {
			continue
		}
		item.Countries = splitCodes(countries)
		items = append(items, item)
	}
	return items, rows.Err()
}

func (h *Handler) listMoneyCountries(ctx context.Context, access repository.MoneyAccess, appCodes []string) ([]moneyCountryDTO, error) {
	if len(appCodes) == 0 {
		return []moneyCountryDTO{}, nil
	}
	where, args := inClause("c.app_code", appCodes)
	rows, err := h.userDB.QueryContext(ctx, `
		SELECT c.app_code, c.country_id, c.country_code, c.country_name, c.country_display_name, c.flag,
		       c.enabled, COALESCE(rc.region_id, 0), c.sort_order
		FROM countries c
		LEFT JOIN region_countries rc
		  ON rc.app_code = c.app_code AND rc.country_code = c.country_code AND rc.status = 'active'
		WHERE c.enabled = TRUE AND `+where+`
		ORDER BY c.app_code ASC, c.sort_order DESC, c.country_name ASC`, args...)
	if err != nil {
		return nil, err
	}
	defer rows.Close()
	items := []moneyCountryDTO{}
	for rows.Next() {
		var item moneyCountryDTO
		if err := rows.Scan(&item.AppCode, &item.CountryID, &item.CountryCode, &item.CountryName, &item.CountryDisplayName, &item.Flag, &item.Enabled, &item.RegionID, &item.SortOrder); err != nil {
			return nil, err
		}
		if !access.All && !access.Allows(item.AppCode, item.RegionID) {
			continue
		}
		items = append(items, item)
	}
	return items, rows.Err()
}

func (h *Handler) performanceAppCodes(ctx context.Context, access repository.MoneyAccess, queryAppCode string) ([]string, error) {
	if appCode := appctx.Normalize(queryAppCode); strings.TrimSpace(queryAppCode) != "" {
		if !moneyAccessAllowsApp(access, appCode) {
			return nil, nil
		}
		return []string{appCode}, nil
	}
	if !access.All {
		return access.AppCodes(), nil
	}
	rows, err := h.walletDB.QueryContext(ctx, `
		SELECT DISTINCT app_code
		FROM external_recharge_orders
		WHERE audience_type = ?
		ORDER BY app_code ASC`, temporaryRechargeAudience)
	if err != nil {
		return nil, err
	}
	defer rows.Close()
	appCodes := []string{}
	for rows.Next() {
		var appCode string
		if err := rows.Scan(&appCode); err != nil {
			return nil, err
		}
		appCodes = append(appCodes, appctx.Normalize(appCode))
	}
	return appCodes, rows.Err()
}

func (h *Handler) listPaidTemporaryOrders(ctx context.Context, appCode string, startAtMS int64, endAtMS int64) ([]paidTemporaryOrder, error) {
	where := `WHERE app_code = ? AND audience_type = ? AND status IN ('paid', 'credited')`
	args := []any{appCode, temporaryRechargeAudience}
	if startAtMS > 0 {
		where += ` AND updated_at_ms >= ?`
		args = append(args, startAtMS)
	}
	if endAtMS > 0 {
		where += ` AND updated_at_ms <= ?`
		args = append(args, endAtMS)
	}
	rows, err := h.walletDB.QueryContext(ctx, `
		SELECT app_code, order_id, usd_minor_amount, status, country_code, provider_code, payment_method_id, pay_url, created_at_ms, updated_at_ms
		FROM external_recharge_orders
		`+where+`
		ORDER BY updated_at_ms DESC, order_id DESC`, args...)
	if err != nil {
		return nil, err
	}
	defer rows.Close()
	orders := []paidTemporaryOrder{}
	for rows.Next() {
		var order paidTemporaryOrder
		if err := rows.Scan(&order.AppCode, &order.OrderID, &order.USDMinorAmount, &order.Status, &order.CountryCode, &order.ProviderCode, &order.PaymentMethodID, &order.PayURL, &order.CreatedAtMS, &order.UpdatedAtMS); err != nil {
			return nil, err
		}
		orders = append(orders, order)
	}
	return orders, rows.Err()
}

func moneyPerformanceSummary(items []moneyPerformanceItemDTO) gin.H {
	var paidLinks int64
	var paidUSDMinor int64
	for _, item := range items {
		paidLinks += item.PaidLinkCount
		paidUSDMinor += item.PaidUSDMinor
	}
	return gin.H{
		"paidLinkCount": paidLinks,
		"paidUsdMinor":  paidUSDMinor,
		"operatorCount": len(items),
	}
}

func moneyScopeDTOsFromModel(scopes []model.UserMoneyScope) []moneyScopeItemDTO {
	out := make([]moneyScopeItemDTO, 0, len(scopes))
	for _, scope := range scopes {
		out = append(out, moneyScopeItemDTO{AppCode: scope.AppCode, RegionID: scope.RegionID})
	}
	return out
}

func scopedAppWhere(access repository.MoneyAccess) (string, []any) {
	if access.All {
		return "", nil
	}
	where, args := inClause("app_code", access.AppCodes())
	return " AND " + where, args
}

func inClause(column string, values []string) (string, []any) {
	if len(values) == 0 {
		return "1 = 0", nil
	}
	placeholders := make([]string, 0, len(values))
	args := make([]any, 0, len(values))
	for _, value := range values {
		placeholders = append(placeholders, "?")
		args = append(args, appctx.Normalize(value))
	}
	return column + " IN (" + strings.Join(placeholders, ",") + ")", args
}

func splitCodes(value string) []string {
	parts := strings.Split(value, ",")
	out := make([]string, 0, len(parts))
	for _, part := range parts {
		part = strings.TrimSpace(part)
		if part != "" {
			out = append(out, part)
		}
	}
	return out
}

func queryUint(c *gin.Context, keys ...string) uint {
	value := strings.TrimSpace(firstQuery(c, keys...))
	if value == "" {
		return 0
	}
	parsed, err := strconv.ParseUint(value, 10, 64)
	if err != nil {
		return 0
	}
	return uint(parsed)
}

func temporaryPaymentCommandID(userID uint, requestID string) string {
	return fmt.Sprintf("admin-temporary:%d:%s", userID, strings.TrimSpace(requestID))
}
