package ether

import (
	"github.com/gogo/protobuf/proto"
	"github.com/pingcap/wormhole/pkg/whpb"
)

type fenceInfo struct {
	origin *whpb.Fence
	jobs   map[uint64]*whpb.Fence
}

func newFenceInfo(fence *whpb.Fence) *fenceInfo {
	return &fenceInfo{
		origin: fence,
		jobs:   make(map[uint64]*whpb.Fence),
	}
}

func (f *fenceInfo) getJobFence(jobID uint64) *whpb.Fence {
	fence := f.jobs[jobID]
	if fence != nil {
		return fence
	}

	return proto.Clone(f.origin).(*whpb.Fence)
}

func (f *fenceInfo) setJobFence(fence *whpb.Fence, jobID uint64) {
	f.jobs[jobID] = fence
}

// fencesInfo contains all fence information.
type fencesInfo struct {
	fences map[uint64]*fenceInfo // for job
}

func newFencesInfo() *fencesInfo {
	return &fencesInfo{
		fences: make(map[uint64]*fenceInfo),
	}
}

func (f *fencesInfo) getJobFence(fenceID uint64, jobID uint64) *whpb.Fence {
	fence, exists := f.fences[fenceID]
	if !exists {
		return nil
	}

	return fence.getJobFence(jobID)
}

func (f *fencesInfo) setJobFence(fence *whpb.Fence, jobID uint64) {
	_, exist := f.fences[fence.GetId()]
	if !exist {
		f.fences[fence.GetId()] = newFenceInfo(fence)
	}

	f.fences[fence.GetId()].setJobFence(fence, jobID)
}

func (f *fencesInfo) setFence(fence *whpb.Fence) {
	f.fences[fence.GetId()] = newFenceInfo(fence)
}

func (f *fencesInfo) isSynced(fenceID uint64, jobID uint64) (bool, bool) {
	fence := f.getJobFence(fenceID, jobID)
	for _, topic := range fence.GetBitmaps() {
		for _, p := range topic.GetPartitionBitmap() {
			if p != 0 {
				return false, false
			}
		}
	}
	for _, topic := range fence.GetBitmaps() {
		for _, p := range topic.GetPartitionMidwayBitmap() {
			if p != 0 {
				return true, false
			}
		}
	}
	return false, true
}
