package app

import (
	"context"
	"fmt"
	"strings"

	"github.com/tidbcloud/AgentTeam/internal/coredb"
	"github.com/tidbcloud/AgentTeam/internal/store/app/webhooks"
	"github.com/tidbcloud/AgentTeam/internal/store/storeerr"
)

// requirePullRequestSubscriptionConnectionForInstallation resolves the
// provider connection from the exact installation the create was authorized
// against — never a workspace-wide installation pick that could borrow
// another installation's credentials.
func (store *Store) requirePullRequestSubscriptionConnectionForInstallation(ctx context.Context, provider string, installationID string, repositoryFullName string, expectedConnectionRef string) (string, error) {
	connectionRef, status, err := resolvePullRequestSubscriptionConnectionForInstallation(ctx, store, provider, installationID, repositoryFullName, expectedConnectionRef)
	if err != nil {
		return "", err
	}
	switch status {
	case webhooks.ServiceEventConnectionReady:
		if strings.TrimSpace(connectionRef) == "" {
			return "", storeerr.BadRequest(string(webhooks.ServiceEventConnectionWorkspaceNotConfigured))
		}
		return strings.TrimSpace(connectionRef), nil
	case webhooks.ServiceEventConnectionResourceNotAccessible:
		return "", storeerr.BadRequest(string(webhooks.ServiceEventConnectionResourceNotAccessible))
	case webhooks.ServiceEventConnectionWorkspaceNotConfigured:
		return "", storeerr.BadRequest(string(webhooks.ServiceEventConnectionWorkspaceNotConfigured))
	default:
		return "", storeerr.BadRequest("provider_connection_unavailable")
	}
}

func (store *Store) resolvePullRequestSubscriptionConnection(ctx context.Context, provider string, workspaceID string, repositoryFullName string, expectedConnectionRef string) (string, webhooks.ServiceEventConnectionStatus, error) {
	normalizedProvider := normalizePullRequestSubscriptionProvider(provider)
	appID, err := pullRequestSubscriptionProviderAppID(normalizedProvider)
	if err != nil {
		return "", webhooks.ServiceEventConnectionWorkspaceNotConfigured, err
	}
	switch normalizedProvider {
	case PullRequestSubscriptionProviderGitHub:
		if _, found, err := store.providerStore().LoadGitHubAppConfigForWorkspace(ctx, workspaceID); err != nil {
			return "", webhooks.ServiceEventConnectionWorkspaceNotConfigured, err
		} else if !found {
			return "", webhooks.ServiceEventConnectionWorkspaceNotConfigured, nil
		}
	case PullRequestSubscriptionProviderGitea:
		if _, found, err := store.providerStore().LoadGiteaAppConfigForWorkspace(ctx, workspaceID); err != nil {
			return "", webhooks.ServiceEventConnectionWorkspaceNotConfigured, err
		} else if !found {
			return "", webhooks.ServiceEventConnectionWorkspaceNotConfigured, nil
		}
	default:
		return "", webhooks.ServiceEventConnectionResourceNotAccessible, nil
	}

	installationID, found, err := activePullRequestSubscriptionServiceInstallationID(ctx, store.db, workspaceID, appID)
	if err != nil {
		return "", webhooks.ServiceEventConnectionWorkspaceNotConfigured, err
	}
	if !found {
		return "", webhooks.ServiceEventConnectionWorkspaceNotConfigured, nil
	}
	return resolvePullRequestSubscriptionConnectionForInstallation(
		ctx,
		store,
		normalizedProvider,
		installationID,
		repositoryFullName,
		expectedConnectionRef,
	)
}

// resolvePullRequestSubscriptionConnectionForInstallation resolves repository
// authority from the exact Service installation selected by the caller. This
// avoids silently consulting another active installation when an Extension
// invocation has already frozen its installation identity.
func resolvePullRequestSubscriptionConnectionForInstallation(
	ctx context.Context,
	store *Store,
	provider string,
	installationID string,
	repositoryFullName string,
	expectedConnectionRef string,
) (string, webhooks.ServiceEventConnectionStatus, error) {
	normalizedProvider := normalizePullRequestSubscriptionProvider(provider)
	connections, err := store.serviceActorStore().ListActiveConnections(ctx, installationID)
	if err != nil {
		return "", webhooks.ServiceEventConnectionWorkspaceNotConfigured, err
	}
	connectionViews := serviceConnectionsToAppViews(connections)
	if len(connectionViews) == 0 {
		return "", webhooks.ServiceEventConnectionWorkspaceNotConfigured, nil
	}

	switch normalizedProvider {
	case PullRequestSubscriptionProviderGitHub:
		connectionRef, status := webhooks.ResolveGitHubServiceEventConnectionFromConnections(connectionViews, repositoryFullName, expectedConnectionRef)
		return connectionRef, status, nil
	case PullRequestSubscriptionProviderGitea:
		connectionRef, status := webhooks.ResolveGiteaServiceEventConnectionFromConnections(connectionViews, repositoryFullName, expectedConnectionRef)
		return connectionRef, status, nil
	default:
		return "", webhooks.ServiceEventConnectionResourceNotAccessible, nil
	}
}

func activePullRequestSubscriptionServiceInstallationID(ctx context.Context, queryer coredb.QueryRower, workspaceID string, appID string) (string, bool, error) {
	row := queryer.QueryRow(ctx, `
SELECT id
FROM service_installations
WHERE workspace_id = $1
  AND service_definition_id = $2
  AND service_kind = 'app'
  AND status = 'active'
LIMIT 1
`, strings.TrimSpace(workspaceID), strings.TrimSpace(appID))
	var installationID string
	if err := row.Scan(&installationID); err != nil {
		if coredb.IsNotFound(err) {
			return "", false, nil
		}
		return "", false, fmt.Errorf("load service event subscription installation: %w", err)
	}
	return strings.TrimSpace(installationID), strings.TrimSpace(installationID) != "", nil
}
