package organization

import (
	"context"
	"fmt"
	"strings"
	"time"

	"github.com/tidbcloud/AgentTeam/internal/coredb"
	"github.com/tidbcloud/AgentTeam/internal/store/model"
	"github.com/tidbcloud/AgentTeam/internal/store/plan"
)

func (txs TxStore) checkQuotaInTx(ctx context.Context, tx coredb.Tx, organizationID string, metric plan.MetricKey, delta int64) error {
	if txs.checkOrganizationQuotaInTx == nil {
		return fmt.Errorf("organization quota checker is not configured")
	}
	return txs.checkOrganizationQuotaInTx(ctx, tx, organizationID, metric, delta)
}

func organizationHasActiveSeat(ctx context.Context, queryer coredb.QueryRower, organizationID string, userID string) (bool, error) {
	row := queryer.QueryRow(ctx, `
SELECT COUNT(*)
FROM (
  SELECT om.user_id AS user_id
  FROM organization_members om
  WHERE om.organization_id = $1
    AND om.user_id = $2
    AND om.status = 'active'
  UNION
  SELECT m.user_id AS user_id
  FROM members m
  JOIN workspaces w ON w.id = m.workspace_id
  WHERE w.organization_id = $1
    AND m.user_id = $2
    AND m.type = 'human'
    AND m.status = 'active'
) seats
`, organizationID, userID)
	var count int64
	if err := row.Scan(&count); err != nil {
		return false, fmt.Errorf("check active organization seat: %w", err)
	}
	return count > 0, nil
}

func (txs TxStore) hasGlobalFeishuServerConfig() bool {
	return strings.TrimSpace(txs.feishuAppID) != "" && strings.TrimSpace(txs.feishuAppSecret) != ""
}

func organizationSyncMetadataView(externalProvider string, externalID string, syncedAt *time.Time, syncMode string, syncSource string, lastSyncRunID string, lastSyncDirectoryRevision int64, lastSyncRunStatus string) OrganizationSyncMetadata {
	return OrganizationSyncMetadata{
		ExternalProvider:          strings.TrimSpace(externalProvider),
		ExternalID:                strings.TrimSpace(externalID),
		SyncedAt:                  syncedAt,
		SyncMode:                  strings.TrimSpace(syncMode),
		SyncSource:                strings.TrimSpace(syncSource),
		LastSyncRunID:             strings.TrimSpace(lastSyncRunID),
		LastSyncDirectoryRevision: lastSyncDirectoryRevision,
		LastSyncRunStatus:         strings.TrimSpace(lastSyncRunStatus),
		ReadOnly:                  strings.TrimSpace(syncMode) != organizationSyncModeLocal,
	}
}

func resolveOrganizationSyncMode(directoryBackend string) (string, error) {
	normalizedDirectoryBackend, err := normalizeOrganizationDirectoryBackend(directoryBackend)
	if err != nil {
		return "", fmt.Errorf("unknown organization directory backend %q", directoryBackend)
	}

	switch normalizedDirectoryBackend {
	case organizationDirectoryBackendEmbedded:
		return organizationSyncModeLocal, nil
	case organizationDirectoryBackendExternalShadow:
		return organizationSyncModeShadow, nil
	case organizationDirectoryBackendExternalAuthority:
		return organizationSyncModeAuthority, nil
	default:
		return "", fmt.Errorf("unknown organization directory backend %q", directoryBackend)
	}
}

func slugifyOrganizationName(name string) string {
	slug := strings.ToLower(strings.TrimSpace(name))
	slug = strings.Map(func(r rune) rune {
		switch {
		case r >= 'a' && r <= 'z':
			return r
		case r >= '0' && r <= '9':
			return r
		default:
			return '-'
		}
	}, slug)
	slug = strings.Trim(slug, "-")
	for strings.Contains(slug, "--") {
		slug = strings.ReplaceAll(slug, "--", "-")
	}
	if len(slug) > 63 {
		slug = strings.TrimRight(slug[:63], "-")
	}
	return slug
}

func defaultWorkspaceNameForUser(user model.User) string {
	name := strings.TrimSpace(user.DisplayName)
	if name == "" {
		name = strings.TrimSpace(user.Name)
	}
	if name == "" && strings.Contains(user.Email, "@") {
		name = strings.TrimSpace(strings.SplitN(user.Email, "@", 2)[0])
	}
	if name == "" {
		name = "Personal"
	}
	return name + "'s Workspace"
}

func rollback(tx coredb.Tx, ctx context.Context) {
	_ = tx.Rollback(ctx)
}

func isUniqueViolation(err error) bool {
	return coredb.IsUniqueViolation(err)
}
