package usecase

import (
	"context"
	"fmt"
	"strings"

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

	"github.com/google/uuid"
)

type stylePresetUseCase struct {
	repo    domrepo.Repository
	persona personadomain.UseCase
}

func NewUseCase(repo domrepo.Repository, persona personadomain.UseCase) domusecase.UseCase {
	return &stylePresetUseCase{repo: repo, persona: persona}
}

func (u *stylePresetUseCase) List(ctx context.Context, tenantID, ownerUID, personaID string) ([]domusecase.PresetSummary, error) {
	if err := u.require(ctx, tenantID, ownerUID, personaID); err != nil {
		return nil, err
	}
	items, err := u.repo.List(ctx, tenantID, ownerUID, personaID)
	if err != nil {
		return nil, err
	}
	out := make([]domusecase.PresetSummary, 0, len(items))
	for _, item := range items {
		out = append(out, toSummary(item))
	}
	return out, nil
}

func (u *stylePresetUseCase) Upsert(ctx context.Context, req domusecase.UpsertRequest) (*domusecase.PresetSummary, error) {
	if err := u.require(ctx, req.TenantID, req.OwnerUID, req.PersonaID); err != nil {
		return nil, err
	}
	name := strings.TrimSpace(req.Name)
	if name == "" {
		return nil, app.For(code.Persona).InputMissingRequired("name is required")
	}
	now := clock.NowUnixNano()
	id := strings.TrimSpace(req.PresetID)
	item := &entity.Preset{ID: id}
	if id == "" || id == "new" {
		item.ID = uuid.NewString()
		item.CreateAt = now
	} else if existing, err := u.repo.Get(ctx, req.TenantID, req.OwnerUID, req.PersonaID, id); err == nil {
		item = existing
	}
	item.TenantID = req.TenantID
	item.OwnerUID = req.OwnerUID
	item.PersonaID = req.PersonaID
	item.Name = name
	item.Tone = strings.TrimSpace(req.Tone)
	item.CTA = cleanList(req.CTA)
	item.BannedWords = cleanList(req.BannedWords)
	item.Notes = strings.TrimSpace(req.Notes)
	item.UpdateAt = now
	if item.CreateAt == 0 {
		item.CreateAt = now
	}
	saved, err := u.repo.Upsert(ctx, item)
	if err != nil {
		return nil, err
	}
	if req.Apply && u.persona != nil {
		profile := formatPresetProfile(saved)
		_, _ = u.persona.Update(ctx, personadomain.UpdateRequest{
			TenantID: req.TenantID, OwnerUID: req.OwnerUID, PersonaID: req.PersonaID,
			Patch: personadomain.PersonaPatch{StyleProfile: &profile},
		})
	}
	out := toSummary(*saved)
	return &out, nil
}

func (u *stylePresetUseCase) Delete(ctx context.Context, tenantID, ownerUID, personaID, presetID string) error {
	if err := u.require(ctx, tenantID, ownerUID, personaID); err != nil {
		return err
	}
	return u.repo.Delete(ctx, tenantID, ownerUID, personaID, presetID)
}

func (u *stylePresetUseCase) require(ctx context.Context, tenantID, ownerUID, personaID string) error {
	if strings.TrimSpace(tenantID) == "" || strings.TrimSpace(ownerUID) == "" {
		return app.For(code.Auth).AuthUnauthorized("missing actor")
	}
	if strings.TrimSpace(personaID) == "" {
		return app.For(code.Persona).InputMissingRequired("persona_id is required")
	}
	if u.persona != nil {
		_, err := u.persona.Get(ctx, tenantID, ownerUID, personaID)
		return err
	}
	return nil
}

func toSummary(item entity.Preset) domusecase.PresetSummary {
	return domusecase.PresetSummary{
		ID: item.ID, PersonaID: item.PersonaID, Name: item.Name, Tone: item.Tone,
		CTA: append([]string(nil), item.CTA...), BannedWords: append([]string(nil), item.BannedWords...),
		Notes: item.Notes, CreateAt: item.CreateAt, UpdateAt: item.UpdateAt,
	}
}

func cleanList(values []string) []string {
	out := make([]string, 0, len(values))
	seen := map[string]struct{}{}
	for _, value := range values {
		trimmed := strings.TrimSpace(value)
		if trimmed == "" {
			continue
		}
		if _, ok := seen[trimmed]; ok {
			continue
		}
		seen[trimmed] = struct{}{}
		out = append(out, trimmed)
	}
	return out
}

func formatPresetProfile(item *entity.Preset) string {
	return fmt.Sprintf("語調：%s\nCTA：%s\n禁用詞：%s\n備註：%s", item.Tone, strings.Join(item.CTA, "、"), strings.Join(item.BannedWords, "、"), item.Notes)
}
