package control

import (
	"strings"
	"time"

	"github.com/tidbcloud/AgentTeam/desktop/internal/token"
	"github.com/tidbcloud/AgentTeam/desktop/internal/uisession"
)

const uiSessionRenewalLeadTime = 5 * time.Minute

type uiSessionControl struct {
	instanceID string
	selections *uisession.Store
}

func NewUISessionControl(instanceID string, selections *uisession.Store) UISessionControl {
	return &uiSessionControl{
		instanceID: strings.TrimSpace(instanceID),
		selections: selections,
	}
}

func (s *uiSessionControl) Create(request CreateUISessionRequest) (UISessionResponse, error) {
	if strings.TrimSpace(request.InstanceID) != s.instanceID {
		return UISessionResponse{}, token.ErrUISessionMismatch
	}
	issue, err := token.EnsureUISession(s.instanceID, request.WindowID)
	if err != nil {
		return UISessionResponse{}, err
	}
	return responseFromIssue(issue), nil
}

func (s *uiSessionControl) Renew(request RenewUISessionRequest) (UISessionResponse, error) {
	if strings.TrimSpace(request.InstanceID) != s.instanceID {
		return UISessionResponse{}, token.ErrUISessionMismatch
	}
	issue, err := token.RenewUISession(
		request.SessionToken,
		s.instanceID,
		request.WindowID,
	)
	if err != nil {
		return UISessionResponse{}, err
	}
	if s.selections != nil {
		s.selections.ExtendLease(issue.Metadata.LogicalSessionID, issue.Metadata.ExpiresAt)
	}
	return responseFromIssue(issue), nil
}

func (s *uiSessionControl) Ensure(request EnsureUISessionRequest) (UISessionResponse, error) {
	if strings.TrimSpace(request.InstanceID) != s.instanceID {
		return UISessionResponse{}, token.ErrUISessionMismatch
	}
	issue, err := token.EnsureUISession(s.instanceID, request.WindowID)
	if err != nil {
		return UISessionResponse{}, err
	}
	if s.selections != nil {
		s.selections.ExtendLease(issue.Metadata.LogicalSessionID, issue.Metadata.ExpiresAt)
	}
	return responseFromIssue(issue), nil
}

func responseFromIssue(issue token.UISessionIssue) UISessionResponse {
	return UISessionResponse{
		SessionToken:    issue.Token,
		ExpiresAt:       issue.Metadata.ExpiresAt,
		RenewAfter:      issue.Metadata.ExpiresAt.Add(-uiSessionRenewalLeadTime),
		LeaseGeneration: issue.Metadata.Generation,
		Disposition:     string(issue.Disposition),
	}
}

func (s *uiSessionControl) Revoke(request RevokeUISessionRequest) error {
	if strings.TrimSpace(request.InstanceID) != s.instanceID {
		return token.ErrUISessionMismatch
	}
	revoked := token.RevokeUISessionWindow(s.instanceID, request.WindowID)
	for _, issue := range revoked {
		if s.selections != nil {
			s.selections.Revoke(issue.Metadata.LogicalSessionID, issue.Metadata.ExpiresAt)
		}
	}
	return nil
}

func (s *uiSessionControl) RevokeInstance(instanceID string) {
	if strings.TrimSpace(instanceID) != s.instanceID {
		return
	}
	revoked := token.RevokeUISessionInstance(s.instanceID)
	for _, issue := range revoked {
		if s.selections != nil {
			s.selections.Revoke(issue.Metadata.LogicalSessionID, issue.Metadata.ExpiresAt)
		}
	}
}
