package parser

import (
	"context"
	"crypto/sha256"
	"encoding/hex"
	"fmt"
	"strings"

	contractevents "bit.admedia.com/scm/ad/adpilot-indexing-code-parser.com/internal/contracts/events"
	"bit.admedia.com/scm/ad/adpilot-indexing-code-parser.com/internal/contracts/graph"
	"bit.admedia.com/scm/ad/adpilot-indexing-code-parser.com/internal/contracts/validate"
)

func (s *Service) publishSuccess(
	ctx context.Context,
	event contractevents.FileChangedEvent,
	jobID string,
	artifact graph.Artifact,
	chunks []contractevents.CodeChunk,
	artifactID, artifactURI string,
) error {
	if s.events == nil {
		return nil
	}

	_ = artifact

	if len(chunks) == 0 {
		return nil
	}

	chunksEvent := contractevents.NewChunksReadyEvent(
		chunksReadyEventID(event.SnapshotID, event.FilePath),
		event.RepoID,
		event.SnapshotID,
		event.CommitSHA,
		event.FilePath,
		event.Language,
		chunks,
	)
	chunksEvent.ArtifactURI = artifactURI

	if err := validate.ChunksReady(chunksEvent); err != nil {
		return fmt.Errorf("validate chunks.ready: %w", err)
	}
	if err := s.events.PublishChunksReady(ctx, chunksEvent); err != nil {
		return fmt.Errorf("publish chunks.ready: %w", err)
	}

	return nil
}

func (s *Service) publishDiagnostics(
	ctx context.Context,
	event contractevents.FileChangedEvent,
	jobID string,
	diagnostics []contractevents.ParserDiagnostic,
) error {
	if len(diagnostics) > 0 {
		s.setJobDiagnostics(jobID, diagnostics)
	}
	if s.finalize != nil && len(diagnostics) > 0 {
		if err := s.finalize.SaveIndexingDiagnostics(ctx, event.RepoID, event.SnapshotID, "code_parse", "file", event.FilePath, jobID, event.EventID, diagnostics); err != nil {
			return fmt.Errorf("persist indexing diagnostics: %w", err)
		}
	}
	if s.events == nil || len(diagnostics) == 0 {
		return nil
	}

	diagEvent := contractevents.NewParserDiagnosticsReadyEvent(
		diagnosticsEventID(jobID),
		event.RepoID,
		event.SnapshotID,
		event.CommitSHA,
		jobID,
		diagnostics,
	)

	if err := validate.ParserDiagnosticsReady(diagEvent); err != nil {
		return fmt.Errorf("validate parser.diagnostics.ready: %w", err)
	}
	if err := s.events.PublishParserDiagnostics(ctx, diagEvent); err != nil {
		return fmt.Errorf("publish parser.diagnostics.ready: %w", err)
	}

	return nil
}

func hashKey(parts ...string) string {
	sum := sha256.Sum256([]byte(strings.Join(parts, "|")))
	return hex.EncodeToString(sum[:4])
}

// JobIDFromEvent returns a deterministic job ID for a files.changed event.
func JobIDFromEvent(event contractevents.FileChangedEvent) string {
	return fmt.Sprintf("job_%s_%s", event.SnapshotID, hashKey(event.FilePath))
}

func jobIDFromEvent(event contractevents.FileChangedEvent) string {
	return JobIDFromEvent(event)
}

func graphArtifactEventID(snapshotID, filePath string) string {
	return fmt.Sprintf("evt_%s_graph_%s", snapshotID, hashKey(filePath))
}

func chunksReadyEventID(snapshotID, filePath string) string {
	return fmt.Sprintf("evt_%s_chunks_%s", snapshotID, hashKey(filePath))
}

func diagnosticsEventID(jobID string) string {
	return fmt.Sprintf("evt_%s_diag", jobID)
}
