package usecase

import (
	"context"
	"strings"

	"haixun-backend/internal/library/clock"
	app "haixun-backend/internal/library/errors"
	"haixun-backend/internal/library/errors/code"
	"haixun-backend/internal/model/crm_contact/domain/entity"
	domrepo "haixun-backend/internal/model/crm_contact/domain/repository"
	domusecase "haixun-backend/internal/model/crm_contact/domain/usecase"

	"github.com/google/uuid"
)

type crmContactUseCase struct {
	repo domrepo.Repository
}

func NewUseCase(repo domrepo.Repository) domusecase.UseCase {
	return &crmContactUseCase{repo: repo}
}

func (u *crmContactUseCase) Create(ctx context.Context, tenantID, ownerUID, brandID, authorID, authorName string) (*domusecase.CRMContactSummary, error) {
	if err := requireActor(tenantID, ownerUID); err != nil {
		return nil, err
	}
	authorID = strings.TrimSpace(authorID)
	if authorID == "" {
		return nil, app.For(code.Persona).InputMissingRequired("author_id is required")
	}
	authorName = strings.TrimSpace(authorName)
	if authorName == "" {
		return nil, app.For(code.Persona).InputMissingRequired("author_name is required")
	}
	now := clock.NowUnixNano()
	contact := &entity.CRMContact{
		ID:         uuid.NewString(),
		TenantID:   tenantID,
		OwnerUID:   ownerUID,
		BrandID:    strings.TrimSpace(brandID),
		AuthorID:   authorID,
		AuthorName: authorName,
		Status:     entity.ContactStatusLead,
		CreateAt:   now,
		UpdateAt:   now,
	}
	if err := u.repo.Create(ctx, contact); err != nil {
		return nil, err
	}
	summary := toSummary(*contact)
	return &summary, nil
}

func (u *crmContactUseCase) Get(ctx context.Context, tenantID, ownerUID, contactID string) (*domusecase.CRMContactSummary, error) {
	if err := requireActor(tenantID, ownerUID); err != nil {
		return nil, err
	}
	contactID = strings.TrimSpace(contactID)
	if contactID == "" {
		return nil, app.For(code.Persona).InputMissingRequired("contact_id is required")
	}
	item, err := u.repo.Get(ctx, tenantID, ownerUID, contactID)
	if err != nil {
		return nil, err
	}
	summary := toSummary(*item)
	return &summary, nil
}

func (u *crmContactUseCase) Update(ctx context.Context, req domusecase.UpdateRequest) (*domusecase.CRMContactSummary, error) {
	if err := requireActor(req.TenantID, req.OwnerUID); err != nil {
		return nil, err
	}
	contactID := strings.TrimSpace(req.ContactID)
	if contactID == "" {
		return nil, app.For(code.Persona).InputMissingRequired("contact_id is required")
	}
	patch := map[string]interface{}{}
	if req.Notes != nil {
		patch["notes"] = strings.TrimSpace(*req.Notes)
	}
	if req.Tags != nil {
		patch["tags"] = *req.Tags
	}
	if req.Status != nil {
		status := strings.TrimSpace(*req.Status)
		if status != "" && status != entity.ContactStatusLead && status != entity.ContactStatusContacted && status != entity.ContactStatusResponded && status != entity.ContactStatusConverted && status != entity.ContactStatusArchived {
			return nil, app.For(code.Persona).InputInvalidFormat("invalid contact status")
		}
		if status != "" {
			patch["status"] = status
		}
	}
	if len(patch) == 0 {
		return nil, app.For(code.Persona).InputMissingRequired("no fields to update")
	}
	patch["update_at"] = clock.NowUnixNano()
	item, err := u.repo.Update(ctx, req.TenantID, req.OwnerUID, contactID, patch)
	if err != nil {
		return nil, err
	}
	summary := toSummary(*item)
	return &summary, nil
}

func (u *crmContactUseCase) Delete(ctx context.Context, tenantID, ownerUID, contactID string) error {
	if err := requireActor(tenantID, ownerUID); err != nil {
		return err
	}
	contactID = strings.TrimSpace(contactID)
	if contactID == "" {
		return app.For(code.Persona).InputMissingRequired("contact_id is required")
	}
	return u.repo.Delete(ctx, tenantID, ownerUID, contactID)
}

func (u *crmContactUseCase) List(ctx context.Context, req domusecase.ListRequest) ([]domusecase.CRMContactSummary, int, error) {
	if err := requireActor(req.TenantID, req.OwnerUID); err != nil {
		return nil, 0, err
	}
	page := req.Page
	pageSize := req.PageSize
	if page < 1 {
		page = 1
	}
	if pageSize < 1 {
		pageSize = 20
	}
	if pageSize > 100 {
		pageSize = 100
	}
	filter := domrepo.ListFilter{
		BrandID: strings.TrimSpace(req.BrandID),
		Status:  strings.TrimSpace(req.Status),
		Tag:     strings.TrimSpace(req.Tag),
		Limit:   pageSize,
		Offset:  (page - 1) * pageSize,
	}
	items, total, err := u.repo.List(ctx, req.TenantID, req.OwnerUID, filter)
	if err != nil {
		return nil, 0, err
	}
	out := make([]domusecase.CRMContactSummary, 0, len(items))
	for _, item := range items {
		out = append(out, toSummary(item))
	}
	return out, total, nil
}

func requireActor(tenantID, ownerUID string) error {
	if strings.TrimSpace(tenantID) == "" || strings.TrimSpace(ownerUID) == "" {
		return app.For(code.Auth).AuthUnauthorized("missing actor")
	}
	return nil
}

func toSummary(item entity.CRMContact) domusecase.CRMContactSummary {
	return domusecase.CRMContactSummary{
		ID:              item.ID,
		BrandID:         item.BrandID,
		AuthorID:        item.AuthorID,
		AuthorName:      item.AuthorName,
		AuthorAvatar:    item.AuthorAvatar,
		AuthorFollowers: item.AuthorFollowers,
		ScanPostID:      item.ScanPostID,
		Notes:           item.Notes,
		Tags:            item.Tags,
		Status:          item.Status,
		OutreachCount:   item.OutreachCount,
		LastContactedAt: item.LastContactedAt,
		CreateAt:        item.CreateAt,
		UpdateAt:        item.UpdateAt,
	}
}
