package roomadmin

import (
	"context"
	"database/sql"
	"encoding/json"
	"fmt"
	"slices"
	"time"

	"hyapp-admin-server/internal/appctx"
)

var roomSeatCountCandidates = []int32{10, 15, 20, 25, 30}

type RoomConfig struct {
	CandidateSeatCounts []int32 `json:"candidateSeatCounts"`
	AllowedSeatCounts   []int32 `json:"allowedSeatCounts"`
	DefaultSeatCount    int32   `json:"defaultSeatCount"`
	UpdatedAtMS         int64   `json:"updatedAtMs"`
}

// GetRoomConfig 读取房间座位数配置；缺行时返回产品默认值，不阻塞首次打开配置页。
func (s *Service) GetRoomConfig(ctx context.Context) (RoomConfig, error) {
	if s.db == nil {
		return RoomConfig{}, fmt.Errorf("room mysql is not configured")
	}
	row := s.db.QueryRowContext(ctx, `
		SELECT allowed_seat_counts, default_seat_count, updated_at_ms
		FROM room_seat_configs
		WHERE app_code = ?
	`, appctx.FromContext(ctx))

	var rawAllowed string
	config := defaultRoomConfig()
	if err := row.Scan(&rawAllowed, &config.DefaultSeatCount, &config.UpdatedAtMS); err != nil {
		if err == sql.ErrNoRows {
			return config, nil
		}
		return RoomConfig{}, err
	}
	if err := json.Unmarshal([]byte(rawAllowed), &config.AllowedSeatCounts); err != nil {
		return RoomConfig{}, err
	}
	return normalizeRoomConfig(config)
}

// UpdateRoomConfig 保存后台房间配置；候选集合固定，后台只控制启用项和默认值。
func (s *Service) UpdateRoomConfig(ctx context.Context, req updateRoomConfigRequest) (RoomConfig, error) {
	if s.db == nil {
		return RoomConfig{}, fmt.Errorf("room mysql is not configured")
	}
	config, err := normalizeRoomConfig(RoomConfig{
		AllowedSeatCounts: req.AllowedSeatCounts,
		DefaultSeatCount:  req.DefaultSeatCount,
		UpdatedAtMS:       time.Now().UTC().UnixMilli(),
	})
	if err != nil {
		return RoomConfig{}, err
	}
	rawAllowed, err := json.Marshal(config.AllowedSeatCounts)
	if err != nil {
		return RoomConfig{}, err
	}
	now := config.UpdatedAtMS
	if _, err := s.db.ExecContext(ctx, `
		INSERT INTO room_seat_configs (app_code, allowed_seat_counts, default_seat_count, created_at_ms, updated_at_ms)
		VALUES (?, ?, ?, ?, ?)
		ON DUPLICATE KEY UPDATE
		  allowed_seat_counts = VALUES(allowed_seat_counts),
		  default_seat_count = VALUES(default_seat_count),
		  updated_at_ms = VALUES(updated_at_ms)
	`, appctx.FromContext(ctx), string(rawAllowed), config.DefaultSeatCount, now, now); err != nil {
		return RoomConfig{}, err
	}
	return config, nil
}

func defaultRoomConfig() RoomConfig {
	return RoomConfig{
		CandidateSeatCounts: append([]int32(nil), roomSeatCountCandidates...),
		AllowedSeatCounts:   append([]int32(nil), roomSeatCountCandidates...),
		DefaultSeatCount:    15,
	}
}

func normalizeRoomConfig(config RoomConfig) (RoomConfig, error) {
	candidateSet := make(map[int32]bool, len(roomSeatCountCandidates))
	for _, candidate := range roomSeatCountCandidates {
		candidateSet[candidate] = true
	}
	seen := make(map[int32]bool, len(config.AllowedSeatCounts))
	allowed := make([]int32, 0, len(config.AllowedSeatCounts))
	for _, value := range config.AllowedSeatCounts {
		if !candidateSet[value] {
			return RoomConfig{}, fmt.Errorf("%w: 座位数只能选择 10、15、20、25、30", ErrInvalidArgument)
		}
		if seen[value] {
			return RoomConfig{}, fmt.Errorf("%w: 座位数不能重复", ErrInvalidArgument)
		}
		seen[value] = true
		allowed = append(allowed, value)
	}
	if len(allowed) == 0 {
		return RoomConfig{}, fmt.Errorf("%w: 至少启用一个座位数", ErrInvalidArgument)
	}
	slices.Sort(allowed)
	if !seen[config.DefaultSeatCount] {
		return RoomConfig{}, fmt.Errorf("%w: 默认座位数必须在已启用座位数中", ErrInvalidArgument)
	}
	config.CandidateSeatCounts = append([]int32(nil), roomSeatCountCandidates...)
	config.AllowedSeatCounts = allowed
	return config, nil
}
