package teamworkflow

import (
	"context"
	"github.com/tidbcloud/AgentTeam/internal/coredb"
	"github.com/tidbcloud/AgentTeam/internal/store/storeerr"
	storeteamworkflow "github.com/tidbcloud/AgentTeam/internal/store/teamworkflow"
	planstore "github.com/tidbcloud/AgentTeam/internal/store/workflow/plan"
)

// SetAvailability archives or restores the Team-linked Plan under the current
// Team owner. The relation and Plan CAS fences are committed together; direct
// publication has no review state to reconcile.
func (service *Service) SetAvailability(ctx context.Context, input LifecycleInput) (LifecycleResult, error) {
	if err := service.validate(); err != nil {
		return LifecycleResult{}, err
	}
	workspaceID, err := required(input.WorkspaceID, "workspaceId", 255)
	if err != nil {
		return LifecycleResult{}, err
	}
	teamID, err := required(input.TeamID, "teamId", 255)
	if err != nil {
		return LifecycleResult{}, err
	}
	teamWorkflowID, err := required(input.TeamWorkflowID, "teamWorkflowId", 64)
	if err != nil {
		return LifecycleResult{}, err
	}
	actorMemberID, err := required(input.ActorMemberID, "actorMemberId", 255)
	if err != nil {
		return LifecycleResult{}, err
	}
	if input.ExpectedRevision <= 0 {
		return LifecycleResult{}, storeerr.BadRequest("expectedRevision must be positive")
	}
	now := normalizedNow(input.Now)
	var result LifecycleResult
	err = coredb.WithTx(ctx, service.db, func(tx coredb.Tx) error {
		team, err := service.teams.InTx(tx).LoadTeam(ctx, workspaceID, teamID)
		if err != nil {
			return err
		}
		if team.CreatedByMemberID != actorMemberID {
			return storeerr.Forbidden("only the Team owner may change Team Workflow availability")
		}
		relations := service.teamWorkflows.InTx(tx)
		relation, err := relations.Load(ctx, workspaceID, teamID, teamWorkflowID, true)
		if err != nil {
			return err
		}
		if relation.DeletedAt != nil {
			return storeerr.Conflict("deleted Team Workflow ownership cannot be restored")
		}
		if relation.Revision != input.ExpectedRevision {
			return storeteamworkflow.RevisionConflictError{Expected: input.ExpectedRevision, Actual: relation.Revision}
		}
		if relation.PlanID == nil || relation.AuthoringState != storeteamworkflow.AuthoringStateIdle {
			return storeerr.Conflict("only an established idle Team Workflow may change availability")
		}
		planStore := service.plans.InTx(tx)
		plan, err := planStore.LoadPlanForUpdate(ctx, workspaceID, *relation.PlanID)
		if err != nil {
			return err
		}
		if input.ExpectedPlanRevision > 0 && plan.Revision != input.ExpectedPlanRevision {
			return planstore.RevisionConflictError{Resource: "plan", Expected: input.ExpectedPlanRevision, Actual: plan.Revision}
		}
		if input.AgentActor != nil {
			if err := planStore.RequireNoMatchingActiveAgentEditWake(ctx, plan, *input.AgentActor); err != nil {
				return err
			}
		}
		alreadyInTargetState := (input.Archived && plan.ArchivedAt != nil) || (!input.Archived && plan.ArchivedAt == nil)
		if alreadyInTargetState {
			result = LifecycleResult{TeamWorkflow: relation, Plan: plan, Replayed: true}
			return nil
		}
		actor := planstore.Actor{Type: planstore.ActorTypeHuman, ID: actorMemberID, MemberID: actorMemberID}
		if input.Archived {
			plan, err = planStore.ArchivePlan(ctx, planstore.ArchivePlanParams{
				WorkspaceID: workspaceID, PlanID: plan.ID, ExpectedRevision: plan.Revision,
				Actor: actor, Now: now,
			})
		} else {
			plan, err = planStore.RestorePlan(ctx, planstore.RestorePlanParams{
				WorkspaceID: workspaceID, PlanID: plan.ID, ExpectedRevision: plan.Revision,
				Actor: actor, Now: now,
			})
		}
		if err != nil {
			return err
		}
		relation, err = relations.AdvanceAvailabilityRevision(ctx, storeteamworkflow.AdvanceAvailabilityRevisionParams{
			WorkspaceID: workspaceID, TeamID: teamID, TeamWorkflowID: teamWorkflowID,
			ExpectedRevision: relation.Revision, Now: now,
		})
		if err != nil {
			return err
		}
		result = LifecycleResult{TeamWorkflow: relation, Plan: plan}
		return nil
	})
	if err != nil {
		return LifecycleResult{}, err
	}
	if !result.Replayed {
		service.emitLifecycleUpdated(result.TeamWorkflow)
	}
	return result, nil
}

// Delete removes one Team association and archives its linked Plan in one
// owner-authorized transaction. Existing published versions remain immutable.
func (service *Service) Delete(ctx context.Context, input DeleteInput) (DeleteResult, error) {
	if err := service.validate(); err != nil {
		return DeleteResult{}, err
	}
	workspaceID, err := required(input.WorkspaceID, "workspaceId", 255)
	if err != nil {
		return DeleteResult{}, err
	}
	teamID, err := required(input.TeamID, "teamId", 255)
	if err != nil {
		return DeleteResult{}, err
	}
	teamWorkflowID, err := required(input.TeamWorkflowID, "teamWorkflowId", 64)
	if err != nil {
		return DeleteResult{}, err
	}
	actorMemberID, err := required(input.ActorMemberID, "actorMemberId", 255)
	if err != nil {
		return DeleteResult{}, err
	}
	if input.ExpectedRevision <= 0 {
		return DeleteResult{}, storeerr.BadRequest("expectedRevision must be positive")
	}
	now := normalizedNow(input.Now)
	var result DeleteResult
	err = coredb.WithTx(ctx, service.db, func(tx coredb.Tx) error {
		team, err := service.teams.InTx(tx).LoadTeam(ctx, workspaceID, teamID)
		if err != nil {
			return err
		}
		if team.CreatedByMemberID != actorMemberID {
			return storeerr.Forbidden("only the Team owner may delete a Team Workflow")
		}
		relations := service.teamWorkflows.InTx(tx)
		relation, err := relations.Load(ctx, workspaceID, teamID, teamWorkflowID, true)
		if err != nil {
			return err
		}
		if relation.DeletedAt != nil {
			result = DeleteResult{TeamWorkflow: relation, Replayed: true}
			return nil
		}
		if relation.Revision != input.ExpectedRevision {
			return storeteamworkflow.RevisionConflictError{Expected: input.ExpectedRevision, Actual: relation.Revision}
		}
		if relation.PlanID != nil {
			planStore := service.plans.InTx(tx)
			plan, err := planStore.LoadPlanForUpdate(ctx, workspaceID, *relation.PlanID)
			if err != nil {
				return err
			}
			if plan.ArchivedAt == nil {
				if _, err := planStore.ArchivePlan(ctx, planstore.ArchivePlanParams{
					WorkspaceID: workspaceID, PlanID: plan.ID, ExpectedRevision: plan.Revision,
					Actor: planstore.Actor{Type: planstore.ActorTypeHuman, ID: actorMemberID, MemberID: actorMemberID}, Now: now,
				}); err != nil {
					return err
				}
			}
		}
		deleted, err := relations.SoftDelete(ctx, storeteamworkflow.SoftDeleteParams{
			WorkspaceID: workspaceID, TeamID: teamID, TeamWorkflowID: teamWorkflowID,
			DeletedByMemberID: actorMemberID, ExpectedRevision: relation.Revision, Now: now,
		})
		if err != nil {
			return err
		}
		result = DeleteResult{TeamWorkflow: deleted}
		return nil
	})
	if err != nil {
		return DeleteResult{}, err
	}
	if !result.Replayed {
		service.emitLifecycleUpdated(result.TeamWorkflow)
	}
	return result, nil
}
