package httpserver

import (
	"fmt"
	"net/http"
	"net/url"
	"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/git"
	"bit.admedia.com/scm/ad/adpilot-indexing-repo-sync.com/internal/service"
)

// MetadataReader exposes persisted repository and snapshot metadata.
type MetadataReader interface {
	GetRepository(repoID string) (domain.Repository, bool)
	GetSnapshotMetadata(repoID, snapshotID string) (domain.Snapshot, bool)
	GetLatestIndexingRun(repoID string) (domain.IndexingRun, bool)
	GetIndexingRunBySnapshot(repoID, snapshotID string) (domain.IndexingRun, bool)
	ListIndexingDiagnostics(repoID, snapshotID string, limit int) ([]domain.IndexingDiagnostic, bool)
}

func handleGetRepository(reader MetadataReader) http.HandlerFunc {
	return func(w http.ResponseWriter, r *http.Request) {
		repoID, err := parseRepoID(r)
		if err != nil {
			writeJSON(w, http.StatusBadRequest, errorResponse{Error: err.Error()})
			return
		}

		repo, ok := reader.GetRepository(repoID)
		if !ok {
			writeJSON(w, http.StatusNotFound, errorResponse{Error: "repository not found"})
			return
		}

		writeJSON(w, http.StatusOK, apicontract.RepositoryFromDomain(repo))
	}
}

func handleGetSnapshot(reader MetadataReader) http.HandlerFunc {
	return func(w http.ResponseWriter, r *http.Request) {
		repoID, err := parseRepoID(r)
		if err != nil {
			writeJSON(w, http.StatusBadRequest, errorResponse{Error: err.Error()})
			return
		}

		snapshotID, err := url.PathUnescape(r.PathValue("snapshot_id"))
		if err != nil || snapshotID == "" {
			writeJSON(w, http.StatusBadRequest, errorResponse{Error: "invalid snapshot_id path"})
			return
		}

		snap, ok := reader.GetSnapshotMetadata(repoID, snapshotID)
		if !ok {
			writeJSON(w, http.StatusNotFound, errorResponse{Error: "snapshot not found"})
			return
		}

		writeJSON(w, http.StatusOK, apicontract.SnapshotFromDomain(snap))
	}
}

func parseRepoID(r *http.Request) (string, error) {
	repoID, err := url.PathUnescape(r.PathValue("repo_id"))
	if err != nil {
		return "", fmt.Errorf("invalid repo_id path")
	}
	if err := git.ParseRepoIDForRead(repoID); err != nil {
		return "", err
	}
	return repoID, nil
}

func handleGetRepoStatus(reader MetadataReader) http.HandlerFunc {
	return func(w http.ResponseWriter, r *http.Request) {
		repoID, err := parseRepoID(r)
		if err != nil {
			writeJSON(w, http.StatusBadRequest, errorResponse{Error: err.Error()})
			return
		}

		repo, ok := reader.GetRepository(repoID)
		if !ok {
			writeJSON(w, http.StatusNotFound, errorResponse{Error: "repository not found"})
			return
		}

		resp := apicontract.RepoStatusResponse{
			RepoID:        repo.RepoID,
			Status:        repo.Status,
			LastCommitSHA: repo.LastCommitSHA,
			DefaultRef:    repo.DefaultRef,
		}
		if !repo.LastSyncAt.IsZero() {
			resp.LastSyncAt = repo.LastSyncAt.UTC().Format(time.RFC3339)
		}
		writeJSON(w, http.StatusOK, resp)
	}
}

var _ MetadataReader = (*service.SyncService)(nil)
