// Copyright Earl Warren <contact@earl-warren.org>
// Copyright Loïc Dachary <loic@dachary.org>
// SPDX-License-Identifier: MIT

package f3

import (
	"encoding/json"
	"fmt"
	"os"

	"github.com/santhosh-tekuri/jsonschema/v6"
)

// Load project data from file, with optional validation
func Load(filename string, data any, validation bool) error {
	bs, err := os.ReadFile(filename)
	if err != nil {
		return err
	}

	if validation {
		err := validate(bs, data)
		if err != nil {
			return err
		}
	}
	return unmarshal(bs, data)
}

func Store(filename string, data any) error {
	f, err := os.Create(filename)
	if err != nil {
		return err
	}
	defer f.Close()
	bs, err := json.MarshalIndent(data, "", "    ")
	if err != nil {
		return err
	}
	if _, err := f.Write(bs); err != nil {
		return err
	}
	if _, err := f.Write([]byte("\n")); err != nil {
		return err
	}
	return nil
}

func unmarshal(bs []byte, data any) error {
	return json.Unmarshal(bs, data)
}

func getSchema(filename string) (*jsonschema.Schema, error) {
	c := jsonschema.NewCompiler()
	return c.Compile(filename)
}

func validate(bs []byte, datatype any) error {
	var v any
	err := unmarshal(bs, &v)
	if err != nil {
		return err
	}

	var schemaFilename string
	switch datatype := datatype.(type) {
	case *User:
		schemaFilename = "schemas/user.json"
	case *Organization:
		schemaFilename = "schemas/organization.json"
	case *Project:
		schemaFilename = "schemas/project.json"
	case *Topic:
		schemaFilename = "schemas/topic.json"
	case *Issue:
		schemaFilename = "schemas/issue.json"
	case *PullRequest:
		schemaFilename = "schemas/pullrequest.json"
	case *Label:
		schemaFilename = "schemas/label.json"
	case *Milestone:
		schemaFilename = "schemas/milestone.json"
	case *Release:
		schemaFilename = "schemas/release.json"
	case *Attachment:
		schemaFilename = "schemas/attachment.json"
	case *Comment:
		schemaFilename = "schemas/comment.json"
	case *Reaction:
		schemaFilename = "schemas/reaction.json"
	case *Repository:
		schemaFilename = "schemas/repository.json"
	case *Review:
		schemaFilename = "schemas/review.json"
	case *ReviewComment:
		schemaFilename = "schemas/reviewcomment.json"
	case *CI:
		schemaFilename = "schemas/ci.json"
	default:
		return fmt.Errorf("file_format:validate: %T does not have a schema that could be used for validation", datatype)
	}

	sch, err := getSchema(schemaFilename)
	if err != nil {
		return err
	}
	return sch.Validate(v)
}
