package mongo

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

	"go.mongodb.org/mongo-driver/bson"
	"go.mongodb.org/mongo-driver/mongo/options"

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

const collectionIndexingDiagnostics = "indexing_diagnostics"

// SaveIndexingDiagnostics persists parser diagnostics in the shared repo-sync database.
func (s *Store) SaveIndexingDiagnostics(
	ctx context.Context,
	repoID, snapshotID, stage, sourceType, sourceID, jobID, eventID string,
	diagnostics []contractevents.ParserDiagnostic,
) error {
	if !s.indexingRunsEnabled || len(diagnostics) == 0 {
		return nil
	}
	if err := ctx.Err(); err != nil {
		return err
	}

	now := time.Now().UTC()
	col := s.indexingRunsCollection(collectionIndexingDiagnostics)
	for i, diagnostic := range diagnostics {
		id := diagnosticID(repoID, snapshotID, stage, sourceID, jobID, diagnostic.Code, diagnostic.Message, i)
		doc := bson.M{
			"diagnostic_id": id,
			"repo_id":       repoID,
			"snapshot_id":   snapshotID,
			"stage":         stage,
			"source_type":   sourceType,
			"source_id":     sourceID,
			"job_id":        jobID,
			"event_id":      eventID,
			"code":          diagnostic.Code,
			"severity":      string(diagnostic.Severity),
			"message":       diagnostic.Message,
			"created_at":    now,
		}
		if diagnostic.FilePath != "" {
			doc["file_path"] = diagnostic.FilePath
		}
		if diagnostic.Line > 0 {
			doc["line"] = diagnostic.Line
		}

		_, err := col.UpdateOne(
			ctx,
			bson.M{"diagnostic_id": id},
			bson.M{"$set": doc},
			options.Update().SetUpsert(true),
		)
		if err != nil {
			return fmt.Errorf("save indexing diagnostic: %w", err)
		}
	}
	return nil
}

func diagnosticID(parts ...interface{}) string {
	values := make([]string, len(parts))
	for i, part := range parts {
		values[i] = fmt.Sprint(part)
	}
	sum := sha256.Sum256([]byte(strings.Join(values, "|")))
	return "diag_" + hex.EncodeToString(sum[:8])
}
