package main

import (
	"errors"
	"fmt"
	"sync"
)

var ErrConflict = errors.New("same key, different payload")

type RequestKey struct{ Tenant, Key string }
type Task struct {
	ID            int
	Tenant, Title string
}
type Store struct {
	mu       sync.Mutex
	next     int
	requests map[RequestKey]Task
	tasks    map[int]Task
	outbox   []int
}

func NewStore() *Store {
	return &Store{requests: make(map[RequestKey]Task), tasks: make(map[int]Task)}
}

// One lock models one atomic transaction, not durable database storage.
func (s *Store) Create(tenant, key, title string) (Task, bool, error) {
	s.mu.Lock()
	defer s.mu.Unlock()
	k := RequestKey{tenant, key}
	if old, ok := s.requests[k]; ok {
		if old.Title != title {
			return Task{}, false, ErrConflict
		}
		return old, true, nil
	}
	s.next++
	t := Task{s.next, tenant, title}
	s.tasks[t.ID] = t
	s.requests[k] = t
	s.outbox = append(s.outbox, t.ID)
	return t, false, nil
}
func main() {
	s := NewStore()
	first, replay, err := s.Create("team-a", "request-1", "写设计")
	fmt.Println(first.ID, replay, err)
	second, replay, err := s.Create("team-a", "request-1", "写设计")
	fmt.Println(second.ID, replay, err)
	_, _, err = s.Create("team-a", "request-1", "改标题")
	fmt.Println(err)
	fmt.Printf("tasks=%d outbox=%d\n", len(s.tasks), len(s.outbox))
}
