package repo

import (
	"context"
	"errors"
	"fmt"

	ubent "github.com/tidbcloud/devops/entity/userbehavior"
	ubmod "github.com/tidbcloud/devops/models/userbehavior"

	"gorm.io/gorm"
)

type GTMLeadDriver interface {
	Create(ctx context.Context, lead *ubent.GTMLead) (*ubent.GTMLead, error)
	GetByID(ctx context.Context, id uint64) (*ubent.GTMLead, error)
	GetByTenantID(ctx context.Context, tenantID uint64) (*ubent.GTMLead, error)
	GetByEmail(ctx context.Context, email string) (*ubent.GTMLead, error)
	Update(ctx context.Context, lead *ubent.GTMLead) (*ubent.GTMLead, error)
	ListQualified(ctx context.Context, limit int) ([]*ubent.GTMLead, error)
	UpdateLeadQualification(ctx context.Context, id uint64, qualified bool, reason string) error
	UpdateLeadUseCaseMatch(ctx context.Context, id uint64, useCase string, reason string) error
}

type gtmLeadDriver driver

func (d *gtmLeadDriver) Create(ctx context.Context, leadent *ubent.GTMLead) (*ubent.GTMLead, error) {
	wdb := d.dbProvider.WriteDB(ctx)
	leadmod := d.cvter.EntityToModel.GTMLead(leadent)

	if err := wdb.Model(&ubmod.GTMLead{}).Create(leadmod).Error; err != nil {
		return nil, fmt.Errorf("create GTM lead failed: %w", err)
	}

	return d.cvter.ModelToEntity.GTMLead(leadmod), nil
}

func (d *gtmLeadDriver) GetByID(ctx context.Context, id uint64) (*ubent.GTMLead, error) {
	rdb := d.dbProvider.ReadDB(ctx)
	var leadmod ubmod.GTMLead

	if err := rdb.Model(&ubmod.GTMLead{}).Where("id = ?", id).First(&leadmod).Error; err != nil {
		if errors.Is(err, gorm.ErrRecordNotFound) {
			return nil, nil
		}
		return nil, fmt.Errorf("get GTM lead by id %d failed: %w", id, err)
	}

	return d.cvter.ModelToEntity.GTMLead(&leadmod), nil
}

func (d *gtmLeadDriver) GetByTenantID(ctx context.Context, tenantID uint64) (*ubent.GTMLead, error) {
	rdb := d.dbProvider.ReadDB(ctx)
	var leadmod ubmod.GTMLead

	if err := rdb.Model(&ubmod.GTMLead{}).Where("tenant_id = ?", tenantID).First(&leadmod).Error; err != nil {
		if errors.Is(err, gorm.ErrRecordNotFound) {
			return nil, nil
		}
		return nil, fmt.Errorf("get GTM lead by tenant_id %d failed: %w", tenantID, err)
	}

	return d.cvter.ModelToEntity.GTMLead(&leadmod), nil
}

func (d *gtmLeadDriver) GetByEmail(ctx context.Context, email string) (*ubent.GTMLead, error) {
	rdb := d.dbProvider.ReadDB(ctx)
	var leadmod ubmod.GTMLead

	if err := rdb.Model(&ubmod.GTMLead{}).Where("email = ?", email).First(&leadmod).Error; err != nil {
		if errors.Is(err, gorm.ErrRecordNotFound) {
			return nil, nil
		}
		return nil, fmt.Errorf("get GTM lead by email %s failed: %w", email, err)
	}

	return d.cvter.ModelToEntity.GTMLead(&leadmod), nil
}

func (d *gtmLeadDriver) Update(ctx context.Context, leadent *ubent.GTMLead) (*ubent.GTMLead, error) {
	wdb := d.dbProvider.WriteDB(ctx)
	leadmod := d.cvter.EntityToModel.GTMLead(leadent)

	if err := wdb.Model(&ubmod.GTMLead{}).Where("id = ?", leadmod.ID).Updates(leadmod).Error; err != nil {
		return nil, fmt.Errorf("update GTM lead %d failed: %w", leadmod.ID, err)
	}

	// Re-fetch to get updated values
	var updated ubmod.GTMLead
	if err := wdb.Model(&ubmod.GTMLead{}).Where("id = ?", leadmod.ID).First(&updated).Error; err != nil {
		return nil, fmt.Errorf("fetch updated GTM lead %d failed: %w", leadmod.ID, err)
	}

	return d.cvter.ModelToEntity.GTMLead(&updated), nil
}

func (d *gtmLeadDriver) ListQualified(ctx context.Context, limit int) ([]*ubent.GTMLead, error) {
	rdb := d.dbProvider.ReadDB(ctx)
	var leadmods []ubmod.GTMLead

	if err := rdb.Model(&ubmod.GTMLead{}).Where("is_qualified = ?", true).Limit(limit).Find(&leadmods).Error; err != nil {
		return nil, fmt.Errorf("list qualified GTM leads failed: %w", err)
	}

	return d.cvter.ModelToEntity.GTMLeads(leadmods), nil
}

func (d *gtmLeadDriver) UpdateLeadQualification(ctx context.Context, id uint64, qualified bool, reason string) error {
	wdb := d.dbProvider.WriteDB(ctx)

	updates := map[string]interface{}{
		"is_qualified":         qualified,
		"qualification_reason": reason,
	}

	if err := wdb.Model(&ubmod.GTMLead{}).Where("id = ?", id).Updates(updates).Error; err != nil {
		return fmt.Errorf("update GTM lead %d qualification failed: %w", id, err)
	}

	return nil
}

func (d *gtmLeadDriver) UpdateLeadUseCaseMatch(ctx context.Context, id uint64, useCase string, reason string) error {
	wdb := d.dbProvider.WriteDB(ctx)

	updates := map[string]interface{}{
		"matched_use_case":      useCase,
		"use_case_match_reason": reason,
	}

	if err := wdb.Model(&ubmod.GTMLead{}).Where("id = ?", id).Updates(updates).Error; err != nil {
		return fmt.Errorf("update GTM lead %d use case match failed: %w", id, err)
	}

	return nil
}
