package verifier

import (
	"crypto/md5"
	"encoding/hex"
	"encoding/json"
	"firefly-launcher/pkg/models"
	"fmt"
	"io"
	"os"
	"path/filepath"

	"github.com/wailsapp/wails/v3/pkg/application"
)

type Verifier struct {
	GamePath       string
	HdiffPath      string
	DiffMapEntries []*models.DiffMapType
}

func NewVerifier(gamePath, hdiffPath string) (*Verifier, error) {
	data, err := os.ReadFile(hdiffPath + "/hdiffmap.json")
	if err != nil {
		return nil, err
	}

	var jsonData struct {
		DiffMap []*models.DiffMapType `json:"diff_map"`
	}
	if err := json.Unmarshal(data, &jsonData); err != nil {
		return nil, err
	}

	return &Verifier{
		GamePath:       gamePath,
		HdiffPath:      hdiffPath,
		DiffMapEntries: jsonData.DiffMap,
	}, nil
}

func (v *Verifier) VerifyAll() error {
	for i, entry := range v.DiffMapEntries {
		application.Get().EmitEvent(
			"hdiffz:progress", map[string]int{
				"progress":    i,
				"maxProgress": len(v.DiffMapEntries),
			})
		if err := check(entry.SourceFileName, entry.SourceFileSize, entry.SourceFileMD5, v.GamePath); err != nil {
			application.Get().EmitEvent("hdiffz:error", err.Error())
			continue
		}
	}
	return nil
}

func check(relPath string, expectedSize int64, expectedMD5, base string) error {
	fullPath := filepath.Join(base, relPath)

	info, err := os.Stat(fullPath)
	if err != nil {
		return fmt.Errorf("file not found: %s", fullPath)
	}

	if info.Size() != expectedSize {
		return fmt.Errorf("file size mismatch for %s: expected %d, got %d",
			fullPath, expectedSize, info.Size())
	}

	md5Hash, err := fileMD5(fullPath)
	if err != nil {
		return fmt.Errorf("error reading %s: %w", fullPath, err)
	}

	if md5Hash != expectedMD5 {
		return fmt.Errorf("md5 mismatch for %s: expected %s, got %s",
			fullPath, expectedMD5, md5Hash)
	}

	return nil
}

func fileMD5(path string) (string, error) {
	f, err := os.Open(path)
	if err != nil {
		return "", err
	}
	defer f.Close()

	h := md5.New()
	if _, err := io.Copy(h, f); err != nil {
		return "", err
	}

	return hex.EncodeToString(h.Sum(nil)), nil
}
