package service_test

import (
	"context"
	"errors"
	"testing"
	"time"

	apicontract "bit.admedia.com/scm/ad/adpilot-indexing-repo-sync.com/internal/contracts/api"
	"bit.admedia.com/scm/ad/adpilot-indexing-repo-sync.com/internal/domain"
	"bit.admedia.com/scm/ad/adpilot-indexing-repo-sync.com/internal/service"
)

func sampleImportRequest() apicontract.ImportRequest {
	return apicontract.ImportRequest{
		ImportJobID:  "import-job-1",
		OrgID:        "org-1",
		ConnectionID: "conn-1",
		Provider:     "github",
		CloneAuth: apicontract.CloneAuth{
			Username:  "x-access-token",
			Password:  "ghp_secret",
			ExpiresAt: time.Now().UTC().Add(time.Hour).Format(time.RFC3339),
		},
		Repos: []apicontract.ImportRepoRef{
			{
				ProviderRepoID: "123",
				FullName:       "acme/widget",
				DefaultBranch:  "main",
				CloneURL:       "https://github.com/acme/widget.git",
			},
		},
	}
}

func TestAcceptImport_Success(t *testing.T) {
	store := newMockMetadataStore()
	svc := service.NewSyncService(&mockGitProvider{result: sampleSyncResult()}, &mockEventPublisher{failOnFileIndex: -1, failOnCommitIndex: -1}, store, testLogger())

	resp, err := svc.AcceptImport(context.Background(), sampleImportRequest())
	if err != nil {
		t.Fatalf("AcceptImport: %v", err)
	}
	if resp.ImportJobID != "import-job-1" || resp.Status != "accepted" {
		t.Fatalf("unexpected response: %+v", resp)
	}
	if len(resp.Jobs) != 1 {
		t.Fatalf("jobs: got %d, want 1", len(resp.Jobs))
	}
	if resp.Jobs[0].RepoID != "github:acme/widget" {
		t.Fatalf("repoId: got %q", resp.Jobs[0].RepoID)
	}

	job, ok, err := store.GetImportJob(context.Background(), "import-job-1")
	if err != nil || !ok {
		t.Fatalf("GetImportJob: ok=%v err=%v", ok, err)
	}
	if job.OrgID != "org-1" || len(job.RepoJobs) != 1 {
		t.Fatalf("stored job: %+v", job)
	}

	repoIDs, err := store.ListRepoIDsByOrg(context.Background(), "org-1")
	if err != nil {
		t.Fatalf("ListRepoIDsByOrg: %v", err)
	}
	if len(repoIDs) != 1 || repoIDs[0] != "github:acme/widget" {
		t.Fatalf("org links: %+v", repoIDs)
	}
}

func TestAcceptImport_InvalidPayload(t *testing.T) {
	svc := newTestService(&mockGitProvider{}, &mockEventPublisher{failOnFileIndex: -1, failOnCommitIndex: -1})

	req := sampleImportRequest()
	req.CloneAuth.Password = ""
	_, err := svc.AcceptImport(context.Background(), req)
	if !errors.Is(err, service.ErrInvalidImportPayload) {
		t.Fatalf("expected ErrInvalidImportPayload, got %v", err)
	}
}

func TestAcceptImport_Duplicate(t *testing.T) {
	store := newMockMetadataStore()
	svc := service.NewSyncService(&mockGitProvider{result: sampleSyncResult()}, &mockEventPublisher{failOnFileIndex: -1, failOnCommitIndex: -1}, store, testLogger())

	req := sampleImportRequest()
	if _, err := svc.AcceptImport(context.Background(), req); err != nil {
		t.Fatalf("first AcceptImport: %v", err)
	}

	resp, err := svc.AcceptImport(context.Background(), req)
	if !errors.Is(err, service.ErrDuplicateImport) {
		t.Fatalf("expected ErrDuplicateImport, got %v", err)
	}
	if resp.ImportJobID != "import-job-1" {
		t.Fatalf("expected existing response, got %+v", resp)
	}
}

func TestAcceptImport_DefaultBranch(t *testing.T) {
	store := newMockMetadataStore()
	svc := service.NewSyncService(&mockGitProvider{result: sampleSyncResult()}, &mockEventPublisher{failOnFileIndex: -1, failOnCommitIndex: -1}, store, testLogger())

	req := sampleImportRequest()
	req.Repos[0].DefaultBranch = ""
	resp, err := svc.AcceptImport(context.Background(), req)
	if err != nil {
		t.Fatalf("AcceptImport: %v", err)
	}
	if resp.Jobs[0].Status != domain.SyncStatusPending {
		t.Fatalf("status: got %q", resp.Jobs[0].Status)
	}
}
