package validate

import (
	"strings"

	contracterrors "bit.admedia.com/scm/ad/adpilot-indexing-repo-sync.com/internal/contracts/errors"
	"bit.admedia.com/scm/ad/adpilot-indexing-repo-sync.com/internal/contracts/events"
	"bit.admedia.com/scm/ad/adpilot-indexing-repo-sync.com/internal/contracts/metadata"
)

func envelope(env metadata.Envelope) error {
	if strings.TrimSpace(env.EventID) == "" {
		return contracterrors.New(contracterrors.CodeMissingField, "event_id", "event_id is required")
	}
	if strings.TrimSpace(env.EventVersion) == "" {
		return contracterrors.New(contracterrors.CodeMissingField, "event_version", "event_version is required")
	}
	if env.EventVersion != metadata.EventVersionV1 {
		return contracterrors.New(contracterrors.CodeUnsupportedVersion, "event_version", "unsupported event version")
	}
	if env.CreatedAt.IsZero() {
		return contracterrors.New(contracterrors.CodeMissingField, "created_at", "created_at is required")
	}
	return nil
}

func repoCommit(repoID, commitSHA string) error {
	if strings.TrimSpace(repoID) == "" {
		return contracterrors.New(contracterrors.CodeMissingField, "repo_id", "repo_id is required")
	}
	if strings.TrimSpace(commitSHA) == "" {
		return contracterrors.New(contracterrors.CodeMissingField, "commit_sha", "commit_sha is required")
	}
	return nil
}

// FileChanged validates a files.changed event.
func FileChanged(event events.FileChangedEvent) error {
	if err := envelope(event.Envelope); err != nil {
		return err
	}
	if err := repoCommit(event.RepoID, event.CommitSHA); err != nil {
		return err
	}
	if strings.TrimSpace(event.SnapshotID) == "" {
		return contracterrors.New(contracterrors.CodeMissingField, "snapshot_id", "snapshot_id is required")
	}
	if strings.TrimSpace(event.FilePath) == "" {
		return contracterrors.New(contracterrors.CodeMissingField, "file_path", "file_path is required")
	}
	if strings.TrimSpace(event.Language) == "" {
		return contracterrors.New(contracterrors.CodeMissingField, "language", "language is required")
	}
	if strings.TrimSpace(string(event.FileKind)) == "" {
		return contracterrors.New(contracterrors.CodeMissingField, "file_kind", "file_kind is required")
	}
	if !event.FileKind.IsValid() {
		return contracterrors.New(contracterrors.CodeInvalidField, "file_kind", "unsupported file_kind")
	}
	if strings.TrimSpace(string(event.ChangeType)) == "" {
		return contracterrors.New(contracterrors.CodeMissingField, "change_type", "change_type is required")
	}
	if !event.ChangeType.IsValid() {
		return contracterrors.New(contracterrors.CodeInvalidField, "change_type", "unsupported change_type")
	}
	return nil
}

// RepoSnapshotReady validates a repo.snapshot.ready event.
func RepoSnapshotReady(event events.RepoSnapshotReadyEvent) error {
	if err := envelope(event.Envelope); err != nil {
		return err
	}
	if err := repoCommit(event.RepoID, event.CommitSHA); err != nil {
		return err
	}
	if strings.TrimSpace(event.SnapshotID) == "" {
		return contracterrors.New(contracterrors.CodeMissingField, "snapshot_id", "snapshot_id is required")
	}
	if strings.TrimSpace(event.Ref) == "" {
		return contracterrors.New(contracterrors.CodeMissingField, "ref", "ref is required")
	}
	return nil
}

// CommitsChanged validates a commits.changed event.
func CommitsChanged(event events.CommitsChangedEvent) error {
	if err := envelope(event.Envelope); err != nil {
		return err
	}
	if err := repoCommit(event.RepoID, event.CommitSHA); err != nil {
		return err
	}
	if strings.TrimSpace(event.SnapshotID) == "" {
		return contracterrors.New(contracterrors.CodeMissingField, "snapshot_id", "snapshot_id is required")
	}
	return nil
}
