package userbehavior

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

	"github.com/expr-lang/expr"
	larkcard "github.com/larksuite/oapi-sdk-go/v3/card"
	"github.com/tidbcloud/devops/entity/event"
	tntent "github.com/tidbcloud/devops/entity/tenant"
	ubent "github.com/tidbcloud/devops/entity/userbehavior"
	larkutil "github.com/tidbcloud/devops/pkg/infra/clients/larkcli/util"
	"github.com/tidbcloud/devops/pkg/service/tenant/region"
	"github.com/tidbcloud/devops/pkg/service/userbehavior/gtm"
	evbus "github.com/tidbcloud/eventbus-datastruct/event"
)

type startupUBEvent struct {
	event.TenantEvent

	tenantName    *string
	bizRegion     *string
	displayRegion *string
	emailDomain   string
	extraInfo     string

	// GTM processing results
	gtmLead          *ubent.GTMLead
	gtmSentEmail     *ubent.GTMSentEmail
	gtmNotifyUserIDs []string // User IDs to @ in GTM result card
}

func (e *startupUBEvent) HandleUBEvent(ctx context.Context) error {
	return nil
}

func (e *startupUBEvent) PreProcess(ctx context.Context) error {
	return nil
}

func (e *startupUBEvent) PostProcess(ctx context.Context) error {
	return nil
}

func (e *startupUBEvent) ProcessTemplate(ctx context.Context, template string) (string, error) {
	return template, nil
}

func (e *startupUBEvent) DefaultText(ctx context.Context) string {
	var tenantName string
	if e.tenantName != nil {
		tenantName = *e.tenantName
	}
	return fmt.Sprintf("[** %s **] New non-individual tenant [**%s**](https://ops.tidbcloud.com/orgs/%d)(id: %d).\nEmail domain is %s \n\n%s",
		e.startupDisplayRegion(),
		tenantName,
		e.OrgId,
		e.OrgId,
		e.emailDomain,
		formatEnrichment(e.extraInfo),
	)
}

func (e *startupUBEvent) GetAvailableParams(ctx context.Context) []string {
	// seems that this function is not used currently
	return []string{}
}

func (e *startupUBEvent) GetUBEventType() ubent.UBEventTp {
	return ubent.UBEventStartup
}

func (e *startupUBEvent) CustomFilter(ctx context.Context, textFilter string) (ret bool, err error) {
	program, err := expr.Compile(textFilter)
	if err != nil {
		return ret, err
	}

	output, err := expr.Run(program, e.TenantEvent)
	if err != nil {
		return ret, err
	}
	ret, ok := output.(bool)
	if !ok {
		return ret, fmt.Errorf("not return a bool type")
	}

	return ret, nil
}

func newstartupUBEvent(ev *event.TenantEvent) UBEvent {
	ubEvent := startupUBEvent{
		TenantEvent: *ev,
		tenantName:  nil,
		bizRegion:   nil,
	}
	return &ubEvent
}

type startupClusterUBEvent struct {
	evbus.DisplayEvent

	emailDomain string
	tenantName  *string
	bizRegion   *string
}

func (e *startupClusterUBEvent) HandleUBEvent(ctx context.Context) error {
	return nil
}

func (e *startupClusterUBEvent) PreProcess(ctx context.Context) error {
	return nil
}

func (e *startupClusterUBEvent) PostProcess(ctx context.Context) error {
	return nil
}

func (e *startupClusterUBEvent) ProcessTemplate(ctx context.Context, template string) (string, error) {
	return template, nil
}

func (e *startupClusterUBEvent) DefaultText(ctx context.Context) string {
	var tenantName string
	if e.tenantName != nil {
		tenantName = *e.tenantName
	}

	return fmt.Sprintf("[** %s **] First essential instance of tenant [**%s**](https://ops.tidbcloud.com/orgs/%d) (id: %d, email domain: %s) is being created. Cluster ID is [**%d**](https://ops.tidbcloud.com/orgs/%d/clusters/%d).",
		*e.bizRegion,
		tenantName,
		e.TenantID,
		e.TenantID,
		e.emailDomain,
		e.ClusterID,
		e.TenantID,
		e.ClusterID,
	)
}

func (e *startupClusterUBEvent) GetAvailableParams(ctx context.Context) []string {
	// seems that this function is not used currently
	return []string{}
}

func (e *startupClusterUBEvent) GetUBEventType() ubent.UBEventTp {
	return ubent.UBEventStartup
}

func (e *startupClusterUBEvent) CustomFilter(ctx context.Context, textFilter string) (ret bool, err error) {
	program, err := expr.Compile(textFilter)
	if err != nil {
		return ret, err
	}

	output, err := expr.Run(program, e.DisplayEvent)
	if err != nil {
		return ret, err
	}
	ret, ok := output.(bool)
	if !ok {
		return ret, fmt.Errorf("not return a bool type")
	}

	return ret, nil
}

func newstartupClusterUBEvent(ev *evbus.DisplayEvent) UBEvent {
	ubEvent := startupClusterUBEvent{
		DisplayEvent: *ev,
	}
	return &ubEvent
}

type startupImportUBEvent struct {
	originEv    *evbus.DisplayEvent
	tenantName  *string
	emailDomain string
	tenantID    uint64
	bizRegion   *string
	clusterID   uint64
}

func (event *startupImportUBEvent) HandleUBEvent(ctx context.Context) error {
	return nil
}

func (event *startupImportUBEvent) PreProcess(ctx context.Context) error {
	return nil
}

func (event *startupImportUBEvent) PostProcess(ctx context.Context) error {
	return nil
}

func (event *startupImportUBEvent) ProcessTemplate(ctx context.Context, template string) (string, error) {
	return template, nil
}

func (event *startupImportUBEvent) DefaultText(ctx context.Context) string {
	var tenantName string
	if event.tenantName != nil {
		tenantName = *event.tenantName
	}
	importStatusText := "finished"
	if event.originEv != nil && event.originEv.DisplayStatus == evbus.EventStatusFailed {
		importStatusText = "failed"
	}

	return fmt.Sprintf("[** %s **] Tenant [%s](https://ops.tidbcloud.com/orgs/%d) (id: %d, email domain: %s) %s an import. Cluster: [%d](https://ops.tidbcloud.com/orgs/%d/clusters/%d)",
		*event.bizRegion,
		tenantName,
		event.tenantID,
		event.tenantID,
		event.emailDomain,
		importStatusText,
		event.clusterID,
		event.tenantID,
		event.clusterID,
	)
}

func (event *startupImportUBEvent) GetAvailableParams(ctx context.Context) []string {
	return clusterEventParams
}

func (event *startupImportUBEvent) GetUBEventType() ubent.UBEventTp {
	return ubent.UBEventStartup
}

func (event *startupImportUBEvent) CustomFilter(ctx context.Context, textFilter string) (ret bool, err error) {
	program, err := expr.Compile(textFilter)
	if err != nil {
		return ret, err
	}

	output, err := expr.Run(program, event.originEv)
	if err != nil {
		return ret, err
	}
	ret, ok := output.(bool)
	if !ok {
		return ret, fmt.Errorf("not return a bool type")
	}

	return ret, nil
}

func newStartupImportUBEvent(ev *evbus.DisplayEvent) UBEvent {
	ubEvent := startupImportUBEvent{
		originEv:   ev,
		tenantName: nil,
		bizRegion:  nil,
		tenantID:   ev.TenantID,
		clusterID:  ev.ClusterID,
	}

	return &ubEvent
}

func (e *startupUBEvent) BuildCustomCard(ctx context.Context) (*larkcard.MessageCard, error) {
	// If GTM queued an email for this event, build custom card
	if e.gtmSentEmail != nil && e.gtmLead != nil {
		return e.buildGTMResultCard()
	}

	// Otherwise use standard card
	return nil, nil
}

func (e *startupUBEvent) buildGTMResultCard() (*larkcard.MessageCard, error) {
	config := larkcard.NewMessageCardConfig().
		WideScreenMode(true).
		EnableForward(true).
		UpdateMulti(false).
		Build()

	cardUrl := ""
	cardLink := larkcard.NewMessageCardURL().
		Url(cardUrl).
		Build()

	header := larkcard.NewMessageCardHeader().
		Template("orange").
		Title(larkcard.NewMessageCardPlainText().
			Content("⏳ AI GTM Email Queued").
			Build()).
		Build()

	// Standard event info (same format as standard card)
	var tenantName string
	if e.tenantName != nil {
		tenantName = *e.tenantName
	}
	standardText := fmt.Sprintf("[** %s **] New non-individual tenant [**%s**](https://ops.tidbcloud.com/orgs/%d)(id: %d).\nEmail domain is %s \n\n%s",
		e.startupDisplayRegion(),
		tenantName,
		e.OrgId,
		e.OrgId,
		e.emailDomain,
		formatEnrichment(e.extraInfo),
	)

	standardDiv := larkcard.NewMessageCardDiv().
		Fields([]*larkcard.MessageCardField{
			larkcard.NewMessageCardField().
				Text(larkcard.NewMessageCardLarkMd().
					Content(standardText).
					Build()).
				IsShort(true).
				Build(),
		}).
		Build()

	// Horizontal line
	hr := larkcard.NewMessageCardHr().Build()

	// GTM processing info
	gtmInfoText := fmt.Sprintf(
		"**✅ Matched Use Case:** %s\n**📧 Email Subject:** %s\n**📬 Queued To:** %s\n**⏳ Scheduled At:** %s",
		e.gtmSentEmail.UseCaseProfile,
		e.gtmSentEmail.Subject,
		e.gtmSentEmail.ToAddress,
		formatLAScheduledAt(e.gtmSentEmail.ScheduledAt),
	)

	// Add @ mentions if configured
	if len(e.gtmNotifyUserIDs) > 0 {
		var mentions []string
		for _, userID := range e.gtmNotifyUserIDs {
			mentions = append(mentions, larkutil.AtUserInCard(userID))
		}
		gtmInfoText = gtmInfoText + "\n\n" + strings.Join(mentions, " ")
	}

	gtmInfoDiv := larkcard.NewMessageCardDiv().
		Fields([]*larkcard.MessageCardField{
			larkcard.NewMessageCardField().
				Text(larkcard.NewMessageCardLarkMd().
					Content(gtmInfoText).
					Build()).
				IsShort(false).
				Build(),
		}).
		Build()

	// Build message card
	messageCard := larkcard.NewMessageCard().
		Config(config).
		Header(header).
		Elements([]larkcard.MessageCardElement{
			standardDiv,
			hr,
			gtmInfoDiv,
		}).
		CardLink(cardLink).
		Build()

	return messageCard, nil
}

func (e *startupUBEvent) startupDisplayRegion() string {
	if e.displayRegion != nil && *e.displayRegion != "" {
		return *e.displayRegion
	}
	if e.bizRegion != nil {
		return *e.bizRegion
	}
	return string(tntent.TenantRegionUnknown)
}

func (e *startupUBEvent) applyHeadquarterDisplayRegion() {
	enrichment, err := gtm.ParseEnrichment(e.extraInfo)
	if err != nil || enrichment.HeadquarterCountryCode == "" {
		return
	}
	headquarterRegion := region.CountryToRegion(enrichment.HeadquarterCountryCode)
	if headquarterRegion != tntent.TenantRegionLATAM && headquarterRegion != tntent.TenantRegionEMEA {
		return
	}
	displayRegion := string(headquarterRegion)
	e.displayRegion = &displayRegion
}

func (e *startupClusterUBEvent) BuildCustomCard(ctx context.Context) (*larkcard.MessageCard, error) {
	return nil, nil // Use standard card
}

func (e *startupImportUBEvent) BuildCustomCard(ctx context.Context) (*larkcard.MessageCard, error) {
	return nil, nil // Use standard card
}

func formatLAScheduledAt(t time.Time) string {
	return t.In(gtmEmailScheduleLocation()).Format(time.RFC3339)
}

// formatEnrichment formats enrichment data for display in Lark cards
// Converts JSON format to readable "Field: Value" format
func formatEnrichment(rawText string) string {
	if rawText == "" {
		return ""
	}

	// Try to parse as JSON
	enrichment, err := gtm.ParseEnrichmentJSON(rawText)
	if err != nil {
		// If JSON parsing fails, return original text (might be already formatted)
		return rawText
	}

	// Format as readable field list
	var parts []string

	if enrichment.CompanyName != "" && enrichment.CompanyName != "Unknown" {
		parts = append(parts, fmt.Sprintf("**Company Name:** %s", enrichment.CompanyName))
	}
	if enrichment.Headquarter != "" && enrichment.Headquarter != "Unknown" {
		parts = append(parts, fmt.Sprintf("**Headquarter:** %s", enrichment.Headquarter))
	}
	if enrichment.Vertical != "" && enrichment.Vertical != "Unknown" {
		parts = append(parts, fmt.Sprintf("**Vertical:** %s", enrichment.Vertical))
	}
	if enrichment.BusinessModel != "" && enrichment.BusinessModel != "Unknown" {
		parts = append(parts, fmt.Sprintf("**Business Model:** %s", enrichment.BusinessModel))
	}
	if enrichment.AnnualRevenue != "" && enrichment.AnnualRevenue != "Unknown" {
		parts = append(parts, fmt.Sprintf("**Annual Revenue:** %s", enrichment.AnnualRevenue))
	}
	if enrichment.FundingSeries != "" && enrichment.FundingSeries != "Unknown" {
		parts = append(parts, fmt.Sprintf("**Funding Series:** %s", enrichment.FundingSeries))
	}
	if enrichment.ConfidenceLevel != "" {
		parts = append(parts, fmt.Sprintf("**AI Confidence Level:** %s", enrichment.ConfidenceLevel))
	}

	if len(parts) == 0 {
		return rawText // Fallback to original if no fields extracted
	}

	return strings.Join(parts, "\n")
}
