package app

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

	"github.com/tidbcloud/AgentTeam/internal/coredb"
	"github.com/tidbcloud/AgentTeam/internal/store/app/installation"
	"github.com/tidbcloud/AgentTeam/internal/store/serviceactor"
)

// UpdateAppDisplayNameForWorkspaceAdmin changes the display name projected by
// one active external App installation. Definition creators and installation
// requesters do not receive mutation authority; only a current workspace
// installation administrator or active App manager can write through this
// workspace-scoped surface.
func (store *Store) UpdateAppDisplayNameForWorkspaceAdmin(
	ctx context.Context,
	userID string,
	workspaceID string,
	installationID string,
	name string,
) (AppInstallationView, error) {
	trimmedName := strings.TrimSpace(name)
	workspaceMember, err := store.requireWorkspaceAccess(ctx, userID, workspaceID)
	if err != nil {
		return AppInstallationView{}, err
	}
	summary, err := store.requireActiveAppRuntimeInstallation(ctx, workspaceID, installationID, nil)
	if err != nil {
		return AppInstallationView{}, err
	}
	if err := store.authorizeAppInstallationManagement(
		ctx,
		store.db,
		workspaceID,
		workspaceMember,
		summary.Definition.ID,
	); err != nil {
		return AppInstallationView{}, err
	}
	if trimmedName == "" {
		return AppInstallationView{}, badRequest("App name is required")
	}

	if err := coredb.WithTx(ctx, store.db, func(tx coredb.Tx) error {
		if err := installation.LockAppInstallationMutationScope(ctx, tx, summary.Definition.ID); err != nil {
			return err
		}
		if _, err := store.revalidateAppInstallationManagementForUpdate(
			ctx,
			tx,
			userID,
			workspaceID,
			workspaceMember.Member.ID,
			summary.Definition.ID,
		); err != nil {
			return err
		}
		txStore := store.serviceActorStore().InTx(tx)
		currentInstallation, err := txStore.LoadInstallationForUpdate(ctx, strings.TrimSpace(installationID))
		if err != nil {
			return err
		}
		if strings.TrimSpace(currentInstallation.WorkspaceID) != strings.TrimSpace(workspaceID) ||
			strings.TrimSpace(currentInstallation.ServiceDefinitionID) != strings.TrimSpace(summary.Definition.ID) ||
			strings.TrimSpace(currentInstallation.ServiceKind) != serviceactor.KindApp ||
			strings.TrimSpace(currentInstallation.Status) != serviceactor.StatusActive {
			return conflict("App installation changed. Retry the rename.")
		}
		if _, err := requirePinnedRuntimeCapability(currentInstallation); err != nil {
			return err
		}
		currentMember, err := txStore.LoadMemberByInstallation(ctx, currentInstallation.ID)
		if err != nil {
			return err
		}
		if strings.TrimSpace(currentMember.WorkspaceID) != strings.TrimSpace(workspaceID) ||
			strings.TrimSpace(currentMember.ServiceDefinitionID) != strings.TrimSpace(summary.Definition.ID) ||
			strings.TrimSpace(currentMember.MemberID) != strings.TrimSpace(summary.Member.MemberID) ||
			strings.TrimSpace(currentMember.ServiceKind) != serviceactor.KindApp ||
			strings.TrimSpace(currentMember.Status) != serviceactor.StatusActive {
			return conflict("App service member changed. Retry the rename.")
		}
		associatedWorkspaceCount, err := appDefinitionAssociatedWorkspaceCount(ctx, tx, summary.Definition.ID)
		if err != nil {
			return err
		}
		if associatedWorkspaceCount > 1 {
			return conflict("This App is associated with multiple workspaces, so its shared name cannot be changed here.")
		}

		now := time.Now().UTC()
		result, err := tx.Exec(ctx, `
UPDATE service_definitions
SET name = $1,
    updated_at = $2
WHERE id = $3
  AND service_kind = 'app'
  AND JSON_UNQUOTE(JSON_EXTRACT(COALESCE(config, JSON_OBJECT()), '$.appKind')) = 'third_party'
`, trimmedName, now, summary.Definition.ID)
		if err != nil {
			return fmt.Errorf("update App display name: %w", err)
		}
		if result.RowsAffected() != 1 {
			return ErrNotFound
		}
		definition, err := store.syncAppServiceDefinition(ctx, tx, summary.Definition.ID, now)
		if err != nil {
			return err
		}
		if strings.TrimSpace(definition.ID) != strings.TrimSpace(summary.Definition.ID) {
			return conflict("App definition changed.")
		}
		_, err = txStore.UpsertMember(ctx, serviceactor.MemberUpsert{
			ID:                    currentMember.ID,
			WorkspaceID:           currentMember.WorkspaceID,
			ServiceDefinitionID:   currentMember.ServiceDefinitionID,
			ServiceInstallationID: currentMember.ServiceInstallationID,
			MemberID:              currentMember.MemberID,
			ServiceKind:           currentMember.ServiceKind,
			Handle:                currentMember.Handle,
			DisplayName:           trimmedName,
			AvatarURL:             currentMember.AvatarURL,
			Status:                currentMember.Status,
			Now:                   now,
		})
		if err != nil {
			return err
		}
		return syncServiceMemberProfile(ctx, tx, workspaceID, currentMember.MemberID, trimmedName, now)
	}); err != nil {
		return AppInstallationView{}, err
	}
	return store.appInstallationViewByID(ctx, workspaceID, strings.TrimSpace(installationID))
}
