package mysql

import (
	"context"
	"database/sql"

	"google.golang.org/protobuf/proto"
	roomv1 "hyapp.local/api/proto/room/v1"
	"hyapp/pkg/appcode"
	roomservice "hyapp/services/room-service/internal/room/service"
)

const ownerCountryRoomExtKey = "owner_country_code"

type ownerCountrySnapshotUpdate struct {
	roomID      string
	roomVersion int64
	payload     []byte
}

// RenameOwnerCountryCode 同事务刷新房间当前列表投影和最新快照中的房主国家码。
// command_log 保留房间发生时事实，因此这里明确只碰当前读模型，供后台国家码重命名任务收敛线上展示态。
func (r *Repository) RenameOwnerCountryCode(ctx context.Context, oldCountryCode string, newCountryCode string, nowMS int64) (roomservice.OwnerCountryCodeRenameResult, error) {
	app := appcode.FromContext(ctx)
	var result roomservice.OwnerCountryCodeRenameResult
	tx, err := r.db.BeginTx(ctx, &sql.TxOptions{})
	if err != nil {
		return roomservice.OwnerCountryCodeRenameResult{}, err
	}
	defer tx.Rollback()

	rows, err := tx.QueryContext(ctx, `
			SELECT room_id, room_version, payload
			FROM room_snapshots
			WHERE app_code = ?
			FOR UPDATE
		`, app)
	if err != nil {
		return roomservice.OwnerCountryCodeRenameResult{}, err
	}

	updates := []ownerCountrySnapshotUpdate{}
	for rows.Next() {
		var update ownerCountrySnapshotUpdate
		if err := rows.Scan(&update.roomID, &update.roomVersion, &update.payload); err != nil {
			_ = rows.Close()
			return roomservice.OwnerCountryCodeRenameResult{}, err
		}
		var snapshot roomv1.RoomSnapshot
		if err := proto.Unmarshal(update.payload, &snapshot); err != nil {
			_ = rows.Close()
			return roomservice.OwnerCountryCodeRenameResult{}, err
		}
		if snapshot.RoomExt == nil || snapshot.RoomExt[ownerCountryRoomExtKey] != oldCountryCode {
			continue
		}
		snapshot.RoomExt[ownerCountryRoomExtKey] = newCountryCode
		body, err := proto.Marshal(&snapshot)
		if err != nil {
			_ = rows.Close()
			return roomservice.OwnerCountryCodeRenameResult{}, err
		}
		update.payload = body
		updates = append(updates, update)
	}
	if err := rows.Close(); err != nil {
		return roomservice.OwnerCountryCodeRenameResult{}, err
	}
	if err := rows.Err(); err != nil {
		return roomservice.OwnerCountryCodeRenameResult{}, err
	}

	listResult, err := tx.ExecContext(ctx, `
		UPDATE room_list_entries
		SET owner_country_code = ?, updated_at_ms = ?
		WHERE app_code = ? AND owner_country_code = ?
	`, newCountryCode, nowMS, app, oldCountryCode)
	if err != nil {
		return roomservice.OwnerCountryCodeRenameResult{}, err
	}
	result.RoomListEntries, _ = listResult.RowsAffected()

	for _, update := range updates {
		// room_version 不递增，避免把低频后台投影修复伪装成 Room Cell 状态版本推进。
		affected, err := tx.ExecContext(ctx, `
				UPDATE room_snapshots
				SET payload = ?, updated_at_ms = ?
				WHERE app_code = ? AND room_id = ? AND room_version = ?
			`, update.payload, nowMS, app, update.roomID, update.roomVersion)
		if err != nil {
			return roomservice.OwnerCountryCodeRenameResult{}, err
		}
		rowsAffected, _ := affected.RowsAffected()
		result.RoomSnapshots += rowsAffected
	}
	if err := tx.Commit(); err != nil {
		return roomservice.OwnerCountryCodeRenameResult{}, err
	}
	return result, nil
}
