package tui

import (
	"errors"
	"fmt"
	"get-container/cmd/hytop/tchart"
	"slices"
	"strings"
	"sync"
	"time"

	tea "github.com/charmbracelet/bubbletea"
	"github.com/charmbracelet/lipgloss"
	linkedlist "github.com/emirpasic/gods/v2/lists/doublylinkedlist"
)

/*
	所有dcu的平均功耗表常态维护
	一旦选中了dcu，选中dcu的平均功耗表常态维护
	ModelPowerDetail.Charts中key为非负数的值，如果存在就更新数据
*/

// ModelPowerDetail 展示DCU功率消耗的Model
type ModelPowerDetail struct {
	PowerCap       map[int]float32                            // dcu功耗墙，即最大功耗，单位为瓦
	DataCache      map[int]*linkedlist.List[tchart.TimePoint] // 功率数据，key为dcu index，value为dcu功率
	DCUDataCache   map[int]*[4]float32                        // 记录dcu与功耗相关的其他信息，key为dcu index，value为dcu的温度、使用率、内存使用率和功率
	height, width  int                                        // 屏幕高度、宽度
	Charts         map[int]*ChartAndArea                      // 图表，key为dcu index，key为-1表示平均值图表，-2表示选中的dcu的平均值图表
	Pids           map[int]int                                // 记录哪些dcu在被使用
	selectedDCU    map[int]bool                               // 记录哪些dcu被选中
	cursor         *int                                       // 光标指向的dcu index
	dcuIndex       []int                                      // dcu index
	DisplaySummary bool                                       // 显示概要信息
	DisplayAvg     bool                                       // 显示功率平均值
	lock           sync.RWMutex                               // 保护DataCache和Charts的锁
	ScreenSplit    map[int][][]ScreenArea                     // 记录屏幕尺寸
	title          string                                     // 标题字符串
}

type ChartAndArea struct {
	chart *MyTimeChart
	area  ScreenArea
	h, l  int
}

func NewModelPower(height, width int) *ModelPowerDetail {
	result := ModelPowerDetail{
		PowerCap:       make(map[int]float32),
		DataCache:      make(map[int]*linkedlist.List[tchart.TimePoint]),
		DCUDataCache:   make(map[int]*[4]float32),
		height:         height,
		width:          width,
		Pids:           make(map[int]int),
		Charts:         make(map[int]*ChartAndArea),
		selectedDCU:    make(map[int]bool),
		dcuIndex:       make([]int, 0, 16),
		cursor:         nil,
		ScreenSplit:    make(map[int][][]ScreenArea),
		DisplaySummary: false,
		DisplayAvg:     false,
		lock:           sync.RWMutex{},
	}
	return &result
}

const (
	ModelPowerTitle = "DCU Pids Temp(°C)  HCU(%)  Mem(%)  PwrCap(W)  AvgPwr(W)\n"
)

var (
	MPStyle = lipgloss.NewStyle().Border(lipgloss.NormalBorder(), false, false, false, true)
)

func (m *ModelPowerDetail) Init() tea.Cmd {
	m.height--
	for i := 1; i < 10; i++ {
		m.ScreenSplit[i] = m.SplitScreen(i)
	}
	m.height++
	m.title = "DCU Power Monitor"

	s := "Press <P> and <Space> to select dcu, Parse <A> to show average"

	extLen := m.width - len(m.title) - len(s)
	if extLen > 0 {
		m.title += strings.Repeat(" ", extLen) + s
	}
	m.title = HeightLightStyle.Render(m.title) + "\n"
	return nil
}

func (m *ModelPowerDetail) Update(imsg tea.Msg) (tea.Model, tea.Cmd) {
	switch msg := imsg.(type) {
	case *ModelMsg:
		// 更新数据
		var powerTotal float32 = 0
		threshold := msg.t.Add(time.Second * (time.Duration(m.width * -2)))
		m.dcuIndex = m.dcuIndex[:0]
		var pwrCap float32 = 0
		info, lock := msg.DCUInfo.GetQuitInfo()
		extAvg := m.DisplayAvg && len(m.selectedDCU) > 0
		var selectedTotal float32 = 0
		m.lock.Lock()
		for k, v := range info {
			tmp := v.PwrCap.OrElse(0)
			m.PowerCap[k] = tmp
			if tmp > 0 {
				pwrCap = tmp
			}
			l, have := m.DataCache[k]
			if !have {
				l = linkedlist.New[tchart.TimePoint]()
			}
			tmp = v.PwrAvg.OrElse(0)
			tp := tchart.TimePoint{Time: msg.t, Value: float64(tmp)}
			l.Append(tp)
			chart, have := m.Charts[k]
			if have {
				chart.chart.PutPoint([]tchart.TimePoint{tp})
			}
			powerTotal += tmp
			if extAvg && m.selectedDCU[k] {
				selectedTotal += tmp
			}
			if !have {
				m.DataCache[k] = l
			}
			// 剔除多余的点
			for {
				point, have := l.Get(0)
				if !have {
					break
				}
				if point.Time.Before(threshold) {
					l.Remove(0)
				} else {
					break
				}
			}
			d, have := m.DCUDataCache[k]
			if !have {
				d := &[4]float32{v.Temp.OrElse(0), v.DCUUTil.OrElse(0), v.MemUsedPerent.OrElse(0), v.PwrAvg.OrElse(0)}
				m.DCUDataCache[k] = d
			} else {
				d[0] = v.Temp.OrElse(0)
				d[1] = v.DCUUTil.OrElse(0)
				d[2] = v.MemUsedPerent.OrElse(0)
				d[3] = v.PwrAvg.OrElse(0)
			}
			m.dcuIndex = append(m.dcuIndex, k)
		}
		lock.Unlock()
		slices.Sort(m.dcuIndex)
		powerTotal /= float32(len(m.dcuIndex))
		selectedTotal /= float32(len(m.selectedDCU))
		l, have := m.DataCache[-1]
		if !have {
			l = linkedlist.New[tchart.TimePoint]()
			m.DataCache[-1] = l
		}
		l.Append(tchart.TimePoint{Time: msg.t, Value: float64(powerTotal)})
		for {
			point, have := l.Get(0)
			if !have {
				break
			}
			if point.Time.Before(threshold) {
				l.Remove(0)
			} else {
				break
			}
		}
		l, have = m.DataCache[-2]
		if !have {
			l = linkedlist.New[tchart.TimePoint]()
			m.DataCache[-2] = l
		}
		for {
			point, have := l.Get(0)
			if !have {
				break
			}
			if point.Time.Before(threshold) {
				l.Remove(0)
			} else {
				break
			}
		}
		chart, have := m.Charts[-1]
		if !have {
			c := NewTimeChart(m.width-1, m.height-2, 0, float64(pwrCap), []lipgloss.Color{lipgloss.Color("#ff0000"), lipgloss.Color("#00ff00ff")})
			chart = &ChartAndArea{chart: c, area: m.ScreenSplit[1][0][0], h: 0, l: 0}
			m.Charts[-1] = chart
		}
		chart.chart.PutPoint([]tchart.TimePoint{{Time: msg.t, Value: float64(powerTotal)}})
		if extAvg {
			chart, have = m.Charts[-2]
			if have {
				chart.chart.PutPoint([]tchart.TimePoint{{Time: msg.t, Value: float64(selectedTotal)}})
				m.Charts[-2] = chart
			}
		}
		m.lock.Unlock()
		m.PowerCap[-1] = pwrCap
		for k := range m.Pids {
			m.Pids[k] = 0
		}
		for k, v := range msg.DCUPidInfo {
			m.Pids[k] = len(v)
		}
	case tea.KeyType:
		m.HandleKey(msg.String())
	case tea.KeyMsg:
		m.HandleKey(msg.String())
	}
	return m, nil
}

// HandleKey 处理按键事件
func (m *ModelPowerDetail) HandleKey(key string) {
	switch key {
	case "p": // 显示概要信息
		m.DisplaySummary = !m.DisplaySummary
	case "a": // 显示平均功率
		m.DisplayAvg = !m.DisplayAvg
	case KeySpace: // 选中/取消dcu
		if !m.DisplaySummary {
			break
		}
		if m.cursor == nil {
			break
		}
		a, b := m.selectedDCU[*m.cursor]
		selected := a && b
		if selected {
			// 已经选中了，现在取消
			delete(m.selectedDCU, *m.cursor)
			m.UpdateCharts(*m.cursor, false)
		} else {
			// 判断
			if len(m.selectedDCU) >= 8 {
				break
			}
			m.selectedDCU[*m.cursor] = true
			m.UpdateCharts(*m.cursor, true)
		}
	case KeyUp:
		if !m.DisplaySummary {
			break
		}
		if m.cursor == nil {
			index := m.dcuIndex[len(m.dcuIndex)-1]
			m.cursor = &index
		} else {
			index := slices.Index(m.dcuIndex, *m.cursor)
			if index == -1 {
				*m.cursor = m.dcuIndex[len(m.dcuIndex)-1]
			} else {
				if index > 0 {
					*m.cursor = m.dcuIndex[index-1]
				}
			}
		}
	case KeyDown:
		if !m.DisplaySummary {
			break
		}
		if m.cursor == nil {
			index := m.dcuIndex[0]
			m.cursor = &index
		} else {
			index := slices.Index(m.dcuIndex, *m.cursor)
			if index == -1 {
				*m.cursor = m.dcuIndex[0]
			} else {
				if index < (len(m.dcuIndex) - 1) {
					*m.cursor = m.dcuIndex[index+1]
				}
			}
		}
	}
}

// SummaryInfo 生成概要信息
func (m *ModelPowerDetail) SummaryInfo() string {
	sb := strings.Builder{}
	sb.WriteString(ModelPowerTitle)
	tmp := len(m.dcuIndex) - 1
	for k, v := range m.dcuIndex {
		d := m.DCUDataCache[v]
		a, b := m.selectedDCU[v]
		selected := a && b
		cursorOn := (m.cursor != nil && *m.cursor == v)
		if !selected && !cursorOn {
			fmt.Fprintf(&sb, "%3d %4d %8.2f  %6.2f  %6.2f  %9.2f %9.2f", v, m.Pids[v], d[0], d[1], d[2], m.PowerCap[v], d[3])
		} else {
			var style lipgloss.Style
			if selected && cursorOn {
				style = HeightSelectedStyle
			} else if selected {
				style = SelectedStyle
			} else {
				style = HeightLightStyle
			}
			s := fmt.Sprintf("%3d %4d %8.2f  %6.2f  %6.2f  %9.2f %9.2f", v, m.Pids[v], d[0], d[1], d[2], m.PowerCap[v], d[3])
			sb.WriteString(style.Render(s))
		}
		if k < tmp {
			sb.WriteByte('\n')
		}
	}
	style := lipgloss.NewStyle().Border(lipgloss.NormalBorder())
	return style.Render(sb.String())
}

// UpdateCharts 解析数据，生成图表结构信息
func (m *ModelPowerDetail) UpdateCharts(index int, isAdd bool) {
	dcuNum := len(m.selectedDCU)
	dcus := make([]int, 0, dcuNum)
	for k, v := range m.selectedDCU {
		if v {
			dcus = append(dcus, k)
		}
	}
	dcuNum = len(dcus)
	slices.Sort(dcus)
	m.lock.Lock()
	if isAdd {
		// 添加dcu
		for k, v := range dcus {
			area, h, l, err := m.getScreenArea(dcuNum, k)
			if err != nil {
				panic(fmt.Sprintf("%v", err))
			}
			chart, have := m.Charts[v]
			if !have {
				// 需要新建图表
				c := createChart(area, float64(m.PowerCap[v]), 0)
				chart = &ChartAndArea{
					chart: c,
					area:  area,
					h:     h,
					l:     l,
				}
				m.Charts[v] = chart
				chart.chart.PutPoint(m.DataCache[v].Values())
				continue
			}
			// 判断图表尺寸是否一致
			if chart.area.Equal(&area) {
				// 一致，仅修改位置即可
				chart.h = h
				chart.l = l
			} else {
				// 尺寸不一致，需要重新生成图表
				chart.chart = createChart(area, float64(m.PowerCap[v]), 0)
				chart.h = h
				chart.l = l
				chart.area = area
				// 新图表添加数据点
				chart.chart.PutPoint(m.DataCache[v].Values())
			}
		}
	} else {
		// 删除dcu
		delete(m.Charts, index)
		for k, v := range dcus {
			area, h, l, err := m.getScreenArea(dcuNum, k)
			if err != nil {
				panic(fmt.Sprintf("%v", err))
			}
			chart := m.Charts[v]
			if chart.area.Equal(&area) {
				// 尺寸一致，无需重新生成，仅修改位置即可
				chart.h = h
				chart.l = l
				continue
			}
			// 尺寸不一致，需要重新生成图表
			chart.chart = createChart(area, float64(m.PowerCap[v]), 0)
			chart.h = h
			chart.l = l
			chart.area = area
			// 新图表添加数据点
			chart.chart.PutPoint(m.DataCache[v].Values())
		}
	}
	// 更新选中dcu的平均值图表
	if dcuNum != 0 {
		l := linkedlist.New[tchart.TimePoint]()
		var points []tchart.TimePoint
		for _, v := range dcus {
			p := m.DataCache[v].Values()
			if points == nil {
				points = p
				continue
			}
			for k := range p {
				v := p[k].Value + points[k].Value
				points[k].Value = v
			}
		}
		for k := range points {
			points[k].Value /= float64(dcuNum)
		}
		l.Append(points...)
		m.DataCache[-2] = l
		chart, have := m.Charts[-2]
		if !have {
			c := NewTimeChart(m.width-1, m.height-2, 0, float64(m.PowerCap[-1]), []lipgloss.Color{lipgloss.Color("#ff0000"), lipgloss.Color("#00ff00ff")})
			chart = &ChartAndArea{chart: c, area: m.ScreenSplit[1][0][0], h: 0, l: 0}
			m.Charts[-2] = chart
		}
		chart.chart.ResetPutPoint(points)
	} else {
		delete(m.Charts, -2)
	}
	m.lock.Unlock()
}

// RenderCharts 渲染图表
func (m *ModelPowerDetail) RenderCharts() string {
	dcuSelected := make([]int, 0, len(m.selectedDCU))
	for k, v := range m.selectedDCU {
		if v {
			dcuSelected = append(dcuSelected, k)
		}
	}
	slices.Sort(dcuSelected)
	selectNum := len(dcuSelected)
	mstr := LowLeightStyle.Render(fmt.Sprintf("%.0fW", m.PowerCap[-1]/2))
	// 显示全部平均功率
	if selectNum == 0 || (selectNum == len(m.dcuIndex) && m.DisplayAvg) {
		chart := m.Charts[-1].chart
		x := genXAxis(chart.width, B)
		str := StackPosition(mstr, chart.ViewWithMiddleLine(), lipgloss.Center, lipgloss.Left) + "\n" + x
		str = StackPosition("DCU: All Avg", str, lipgloss.Top, lipgloss.Left)
		str = MPStyle.Render(str)
		return str
	} else if m.DisplayAvg {
		// 显示选中dcu的平均功率图表
		chart := m.Charts[-2].chart
		x := genXAxis(chart.width, B)
		str := StackPosition(mstr, chart.ViewWithMiddleLine(), lipgloss.Center, lipgloss.Left) + "\n" + x
		strDCU := strings.ReplaceAll(strings.Trim(fmt.Sprintf("%v", dcuSelected), "[]"), " ", ",")
		str = StackPosition(fmt.Sprintf("DCU: %s Avg", strDCU), str, lipgloss.Top, lipgloss.Left)
		return MPStyle.Render(str)
	} else {
		// 显示选中dcu的图表
		areas := m.ScreenSplit[selectNum]
		pa, err := parseAreas(areas)
		if err != nil {
			panic(err.Error())
		}
		strs := make([]string, 0, selectNum)
		for _, v := range dcuSelected {
			chart := m.Charts[v].chart
			str := StackPosition(mstr, chart.ViewWithMiddleLine(), lipgloss.Center, lipgloss.Left)
			str = StackPosition(fmt.Sprintf("DCU: %d", v), str, lipgloss.Top, lipgloss.Left)
			str += "\n"
			str += genXAxis(chart.width, B)
			strs = append(strs, MPStyle.Render(str))
		}
		lines := make(map[int]string)
		for k, v := range strs {
			po := pa[k]
			l, have := lines[po[0]]
			if !have {
				l = v
				lines[po[0]] = l
			} else {
				lines[po[0]] = lipgloss.JoinHorizontal(lipgloss.Top, l, v)
			}
		}
		switch len(lines) {
		case 1:
			return lines[0]
		case 2:
			return lipgloss.JoinVertical(lipgloss.Left, lines[0], lines[1])
		case 3:
			return lipgloss.JoinVertical(lipgloss.Left, lines[0], lines[1], lines[2])
		default:
			panic("error line number")
		}
	}
}

func (m *ModelPowerDetail) View() string {
	rl := m.lock.RLocker()
	rl.Lock()
	defer rl.Unlock()
	if m.DisplaySummary {
		summary := m.SummaryInfo()
		charts := m.RenderCharts()
		return m.title + StackPosition(summary, charts, lipgloss.Center, lipgloss.Center)
	} else {
		return m.title + m.RenderCharts()
	}
}

// getScreenArea 获取指定索引的屏幕区域尺寸、所在的行、列
func (m *ModelPowerDetail) getScreenArea(num, index int) (ScreenArea, int, int, error) {
	if num > 9 || num <= 0 {
		return ScreenArea{}, 0, 0, errors.New("num out of range")
	}
	if index < 0 || index >= num {
		return ScreenArea{}, 0, 0, errors.New("index out of range")
	}
	if m.ScreenSplit == nil {
		return ScreenArea{}, 0, 0, errors.New("Model PowerDetail not init")
	}
	target := m.ScreenSplit[num]
	switch num {
	case 1:
		return target[0][0], 0, 0, nil
	case 2:
		switch index {
		case 0:
			return target[0][0], 0, 0, nil
		case 1:
			return target[1][0], 1, 0, nil
		}
	case 3, 4:
		h := index / 2
		l := index % 2
		return target[h][l], h, l, nil
	case 5, 6, 8, 9:
		h := index / 3
		l := index % 3
		return target[h][l], h, l, nil
	case 7:
		switch index {
		case 0, 1, 2:
			return target[0][index], 0, index, nil
		case 3, 4:
			return target[1][index-3], 1, index - 3, nil
		case 5, 6:
			return target[2][index-5], 2, index - 5, nil
		}
	}
	return ScreenArea{}, 0, 0, errors.New("Model PowerDetail unknown error")
}

// SplitScreen 分割屏幕，得到每个区域的尺寸，返回结果为二维切片，第一维是行，第二维是列
func (m *ModelPowerDetail) SplitScreen(num int) [][]ScreenArea {
	if num <= 0 {
		return nil
	}
	result := make([][]ScreenArea, 0, 3)
	result = append(result, make([]ScreenArea, 0, 3))
	switch num {
	case 1:
		result[0] = append(result[0], NewScreenArea(m.width, m.height))
	case 2:
		result = append(result, make([]ScreenArea, 0, 1))
		result[0] = append(result[0], NewScreenArea(m.width, m.height/2))
		result[1] = append(result[1], NewScreenArea(m.width, m.height/2))
		if m.height%2 != 0 {
			result[0][0].h++
		}
	case 3:
		result = append(result, make([]ScreenArea, 0, 1))
		result[0] = append(result[0], NewScreenArea(m.width/2, m.height/2), NewScreenArea(m.width/2, m.height/2))
		result[1] = append(result[1], NewScreenArea(m.width, m.height/2))
		if m.width%2 != 0 {
			result[0][0].w++
		}
		if m.height%2 != 0 {
			result[0][0].h++
			result[0][1].h++
		}
	case 4:
		result = append(result, make([]ScreenArea, 0, 1))
		result[0] = append(result[0], NewScreenArea(m.width/2, m.height/2), NewScreenArea(m.width/2, m.height/2))
		result[1] = append(result[1], NewScreenArea(m.width/2, m.height/2), NewScreenArea(m.width/2, m.height/2))
		if m.width%2 != 0 {
			result[0][0].w++
			result[1][0].w++
		}
		if m.height%2 != 0 {
			result[0][0].h++
			result[0][1].h++
		}
	case 5: // 两行，3，2
		result = append(result, make([]ScreenArea, 0, 2))
		result[0] = append(result[0], NewScreenArea(m.width/3, m.height/2), NewScreenArea(m.width/3, m.height/2), NewScreenArea(m.width/3, m.height/2))
		result[1] = append(result[1], NewScreenArea(m.width/2, m.height/2), NewScreenArea(m.width/2, m.height/2))
		if m.width%2 != 0 {
			result[1][0].w++
		}
		for l := 0; l < m.width%3; l++ {
			result[0][l].w++
		}
		if m.height%2 != 0 {
			for l := range result[0] {
				result[0][l].h++
			}
		}
	case 6: // 两行，3，3
		result = append(result, make([]ScreenArea, 0, 3))
		result[0] = append(result[0], NewScreenArea(m.width/3, m.height/2), NewScreenArea(m.width/3, m.height/2), NewScreenArea(m.width/3, m.height/2))
		result[1] = append(result[1], NewScreenArea(m.width/3, m.height/2), NewScreenArea(m.width/3, m.height/2), NewScreenArea(m.width/3, m.height/2))
		for h := range result {
			for l := 0; l < m.width%3; l++ {
				result[h][l].w++
			}
		}
		if m.height%2 != 0 {
			for l := range result[0] {
				result[0][l].h++
			}
		}
	case 7: // 三行，3，2，2
		result = append(result, make([]ScreenArea, 0, 2), make([]ScreenArea, 0, 2))
		result[0] = append(result[0], NewScreenArea(m.width/3, m.height/3), NewScreenArea(m.width/3, m.height/3), NewScreenArea(m.width/3, m.height/3))
		result[1] = append(result[1], NewScreenArea(m.width/2, m.height/3), NewScreenArea(m.width/2, m.height/3))
		result[2] = append(result[2], NewScreenArea(m.width/2, m.height/3), NewScreenArea(m.width/2, m.height/3))
		for h := 0; h < m.height%3; h++ {
			for l := range result[h] {
				result[h][l].h++
			}
		}
		for l := 0; l < m.width%3; l++ {
			result[0][l].w++
		}
		if m.width%2 != 0 {
			result[1][0].w++
			result[1][1].w++
			result[2][0].w++
			result[2][1].w++
		}
	case 8: // 三行，3，3，2
		result = append(result, make([]ScreenArea, 0, 3), make([]ScreenArea, 0, 2))
		result[0] = append(result[0], NewScreenArea(m.width/3, m.height/3), NewScreenArea(m.width/3, m.height/3), NewScreenArea(m.width/3, m.height/3))
		result[1] = append(result[1], NewScreenArea(m.width/3, m.height/3), NewScreenArea(m.width/3, m.height/3), NewScreenArea(m.width/3, m.height/3))
		result[2] = append(result[2], NewScreenArea(m.width/2, m.height/3), NewScreenArea(m.width/2, m.height/3))
		for h := 0; h < m.height%3; h++ {
			for l := range result[h] {
				result[h][l].h++
			}
		}
		for h := range result[:2] {
			for l := 0; l < m.width%3; l++ {
				result[h][l].w++
			}
		}
		if m.width%2 != 0 {
			result[2][0].w++
		}
	case 9:
		result = append(result, make([]ScreenArea, 0, 3), make([]ScreenArea, 0, 3))
		result[0] = append(result[0], NewScreenArea(m.width/3, m.height/3), NewScreenArea(m.width/3, m.height/3), NewScreenArea(m.width/3, m.height/3))
		result[1] = append(result[1], NewScreenArea(m.width/3, m.height/3), NewScreenArea(m.width/3, m.height/3), NewScreenArea(m.width/3, m.height/3))
		result[2] = append(result[2], NewScreenArea(m.width/3, m.height/3), NewScreenArea(m.width/3, m.height/3), NewScreenArea(m.width/3, m.height/3))
		for h := 0; h < m.height%3; h++ {
			for l := range result[h] {
				result[h][l].h++
			}
		}
		for h := range result {
			for l := 0; l < m.width%3; l++ {
				result[h][l].w++
			}
		}
	default:
		return nil
	}
	return result
}

type ScreenArea struct {
	w, h int
}

func (sa *ScreenArea) Equal(other *ScreenArea) bool {
	return sa.h == other.h && sa.w == other.w
}

func NewScreenArea(w, h int) ScreenArea {
	return ScreenArea{
		w: w,
		h: h,
	}
}

func createChart(area ScreenArea, max, min float64) *MyTimeChart {
	return NewTimeChart(area.w-1, area.h-1, min, max, []lipgloss.Color{lipgloss.Color("#ff0000"), lipgloss.Color("#00ff00ff")})
}

func parseAreas(areas [][]ScreenArea) (map[int][2]int, error) {
	if areas == nil {
		return nil, errors.New("error args is null")
	}
	index := 0
	result := make(map[int][2]int)
	for kout, vout := range areas {
		for kin := range vout {
			result[index] = [2]int{kout, kin}
			index++
		}
	}
	return result, nil
}
