package mongo

import (
	"context"
	"fmt"

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

const (
	collectionRepositories  = "repositories"
	collectionSnapshots     = "snapshots"
	collectionSyncJobs      = "sync_jobs"
	collectionImportJobs    = "import_jobs"
	collectionIndexingRuns  = "indexing_runs"
	collectionSnapshotFiles = "snapshot_files"
	collectionDiagnostics   = "indexing_diagnostics"
	collectionOrgRepoLinks  = "org_repository_links"
)

// EnsureIndexes creates required MongoDB indexes.
func (s *Store) EnsureIndexes(ctx context.Context) error {
	if err := s.ensureRepositoryIndexes(ctx); err != nil {
		return err
	}
	if err := s.ensureSnapshotIndexes(ctx); err != nil {
		return err
	}
	if err := s.ensureSyncJobIndexes(ctx); err != nil {
		return err
	}
	if err := s.ensureImportJobIndexes(ctx); err != nil {
		return err
	}
	if err := s.ensureOrgRepositoryLinkIndexes(ctx); err != nil {
		return err
	}
	if err := s.ensureIndexingRunIndexes(ctx); err != nil {
		return err
	}
	if err := s.ensureSnapshotFileIndexes(ctx); err != nil {
		return err
	}
	return s.ensureDiagnosticIndexes(ctx)
}

func (s *Store) ensureRepositoryIndexes(ctx context.Context) error {
	_, err := s.collection(collectionRepositories).Indexes().CreateOne(ctx, mongo.IndexModel{
		Keys:    bson.D{{Key: "repo_id", Value: 1}},
		Options: options.Index().SetUnique(true),
	})
	if err != nil {
		return fmt.Errorf("create repositories index: %w", err)
	}
	return nil
}

func (s *Store) ensureSnapshotIndexes(ctx context.Context) error {
	_, err := s.collection(collectionSnapshots).Indexes().CreateOne(ctx, mongo.IndexModel{
		Keys:    bson.D{{Key: "snapshot_id", Value: 1}},
		Options: options.Index().SetUnique(true),
	})
	if err != nil {
		return fmt.Errorf("create snapshots snapshot_id index: %w", err)
	}

	_, err = s.collection(collectionSnapshots).Indexes().CreateOne(ctx, mongo.IndexModel{
		Keys: bson.D{
			{Key: "repo_id", Value: 1},
			{Key: "created_at", Value: -1},
		},
	})
	if err != nil {
		return fmt.Errorf("create snapshots repo_id index: %w", err)
	}
	return nil
}

func (s *Store) ensureSyncJobIndexes(ctx context.Context) error {
	_, err := s.collection(collectionSyncJobs).Indexes().CreateOne(ctx, mongo.IndexModel{
		Keys:    bson.D{{Key: "job_id", Value: 1}},
		Options: options.Index().SetUnique(true),
	})
	if err != nil {
		return fmt.Errorf("create sync_jobs job_id index: %w", err)
	}

	_, err = s.collection(collectionSyncJobs).Indexes().CreateOne(ctx, mongo.IndexModel{
		Keys: bson.D{
			{Key: "repo_id", Value: 1},
			{Key: "started_at", Value: -1},
		},
	})
	if err != nil {
		return fmt.Errorf("create sync_jobs repo_id index: %w", err)
	}
	return nil
}

func (s *Store) ensureImportJobIndexes(ctx context.Context) error {
	_, err := s.collection(collectionImportJobs).Indexes().CreateOne(ctx, mongo.IndexModel{
		Keys:    bson.D{{Key: "import_job_id", Value: 1}},
		Options: options.Index().SetUnique(true),
	})
	if err != nil {
		return fmt.Errorf("create import_jobs import_job_id index: %w", err)
	}
	return nil
}

func (s *Store) ensureIndexingRunIndexes(ctx context.Context) error {
	_, err := s.collection(collectionIndexingRuns).Indexes().CreateOne(ctx, mongo.IndexModel{
		Keys:    bson.D{{Key: "indexing_run_id", Value: 1}},
		Options: options.Index().SetUnique(true),
	})
	if err != nil {
		return fmt.Errorf("create indexing_runs indexing_run_id index: %w", err)
	}

	_, err = s.collection(collectionIndexingRuns).Indexes().CreateOne(ctx, mongo.IndexModel{
		Keys: bson.D{
			{Key: "repo_id", Value: 1},
			{Key: "started_at", Value: -1},
		},
	})
	if err != nil {
		return fmt.Errorf("create indexing_runs repo_id index: %w", err)
	}

	_, err = s.collection(collectionIndexingRuns).Indexes().CreateOne(ctx, mongo.IndexModel{
		Keys: bson.D{
			{Key: "repo_id", Value: 1},
			{Key: "snapshot_id", Value: 1},
		},
	})
	if err != nil {
		return fmt.Errorf("create indexing_runs snapshot index: %w", err)
	}
	return nil
}

func (s *Store) ensureSnapshotFileIndexes(ctx context.Context) error {
	_, err := s.collection(collectionSnapshotFiles).Indexes().CreateOne(ctx, mongo.IndexModel{
		Keys: bson.D{
			{Key: "repo_id", Value: 1},
			{Key: "snapshot_id", Value: 1},
		},
	})
	if err != nil {
		return fmt.Errorf("create snapshot_files repo snapshot index: %w", err)
	}

	_, err = s.collection(collectionSnapshotFiles).Indexes().CreateOne(ctx, mongo.IndexModel{
		Keys: bson.D{
			{Key: "repo_id", Value: 1},
			{Key: "snapshot_id", Value: 1},
			{Key: "file_path", Value: 1},
		},
		Options: options.Index().SetUnique(true),
	})
	if err != nil {
		return fmt.Errorf("create snapshot_files file_path index: %w", err)
	}
	return nil
}

func (s *Store) ensureOrgRepositoryLinkIndexes(ctx context.Context) error {
	_, err := s.collection(collectionOrgRepoLinks).Indexes().CreateOne(ctx, mongo.IndexModel{
		Keys: bson.D{
			{Key: "org_id", Value: 1},
			{Key: "repo_id", Value: 1},
		},
		Options: options.Index().SetUnique(true),
	})
	if err != nil {
		return fmt.Errorf("create org_repository_links index: %w", err)
	}

	_, err = s.collection(collectionOrgRepoLinks).Indexes().CreateOne(ctx, mongo.IndexModel{
		Keys: bson.D{{Key: "org_id", Value: 1}},
	})
	if err != nil {
		return fmt.Errorf("create org_repository_links org_id index: %w", err)
	}
	return nil
}

func (s *Store) ensureDiagnosticIndexes(ctx context.Context) error {
	col := s.collection(collectionDiagnostics)

	_, err := col.Indexes().CreateOne(ctx, mongo.IndexModel{
		Keys:    bson.D{{Key: "diagnostic_id", Value: 1}},
		Options: options.Index().SetUnique(true),
	})
	if err != nil {
		return fmt.Errorf("create indexing_diagnostics diagnostic_id index: %w", err)
	}

	_, err = col.Indexes().CreateOne(ctx, mongo.IndexModel{
		Keys: bson.D{
			{Key: "repo_id", Value: 1},
			{Key: "snapshot_id", Value: 1},
			{Key: "created_at", Value: -1},
		},
	})
	if err != nil {
		return fmt.Errorf("create indexing_diagnostics snapshot index: %w", err)
	}
	return nil
}
