package jmdict

import (
	"compress/gzip"
	"fmt"
	"math/rand"
	"os"
	"sync"

	"github.com/samber/lo"
	"github.com/themoeway/jmdict-go"
)

type JMdictProvider struct {
	mtx     sync.Mutex
	loadErr error
	jdict   *jmdict.Jmdict
}

func Load() *JMdictProvider {
	provider := &JMdictProvider{}

	go func(provider *JMdictProvider) {
		provider.mtx.Lock()
		defer provider.mtx.Unlock()

		f, err := os.Open("./3rdparty/JMdict_e.gz")
		if err != nil {
			provider.loadErr = err
			return
		}

		defer f.Close()

		gzReader, err := gzip.NewReader(f)
		if err != nil {
			provider.loadErr = err
			return
		}

		jdict, _, err := jmdict.LoadJmdict(gzReader)
		if err != nil {
			provider.loadErr = err
			return
		}

		provider.jdict = &jdict
	}(provider)

	return provider
}

func (j *JMdictProvider) Provide() (string, error) {
	j.mtx.Lock()
	defer j.mtx.Unlock()

	if j.err() != nil {
		return "", j.err()
	}

	idx := rand.Int31n(int32(len(j.jdict.Entries)))
	return j.readings(idx)[0], nil
}

func (j *JMdictProvider) readings(i int32) []string {
	return lo.Map(j.jdict.Entries[i].Readings, func(r jmdict.JmdictReading, _ int) string {
		return r.Reading
	})
}

func (j *JMdictProvider) Ready() (bool, error) {
	j.mtx.Lock()
	defer j.mtx.Unlock()
	if j.loadErr != nil {
		return false, j.loadErr
	}
	return j.jdict != nil, nil
}

func (j *JMdictProvider) err() error {
	if j.loadErr != nil {
		return j.loadErr
	}

	if j.jdict == nil {
		return fmt.Errorf("provider is not ready")
	}

	return nil
}