package usecase

import (
	"context"
	"fmt"
	"strings"

	"apps/backend/internal/module/appnotif/domain"

	"github.com/google/uuid"
)

type Service struct {
	Repo domain.Repository
}

func New(repo domain.Repository) *Service {
	return &Service{Repo: repo}
}

func (s *Service) List(ctx context.Context, ownerUID int64) ([]*domain.Notification, error) {
	return s.Repo.ListByOwner(ctx, ownerUID)
}

func (s *Service) UnreadCount(ctx context.Context, ownerUID int64) (int64, error) {
	return s.Repo.UnreadCount(ctx, ownerUID)
}

func (s *Service) MarkRead(ctx context.Context, ownerUID int64, id string) error {
	return s.Repo.MarkRead(ctx, ownerUID, id)
}

func (s *Service) MarkAllRead(ctx context.Context, ownerUID int64) error {
	return s.Repo.MarkAllRead(ctx, ownerUID)
}

// NotifyJobTerminal — 相容舊介面；改走 NotifyJobState（upsert 同一 job 一則）
func (s *Service) NotifyJobTerminal(ctx context.Context, ownerUID int64, jobID, status, summary string) error {
	return s.NotifyJobState(ctx, ownerUID, jobID, "", status, summary, 100)
}

// NotifyJobState — 同一 job 只保留一則通知，進度更新時改寫 title/body（鈴鐺即時有進度）
func (s *Service) NotifyJobState(ctx context.Context, ownerUID int64, jobID, templateType, status, summary string, percent int) error {
	if ownerUID <= 0 || jobID == "" {
		return nil
	}
	title := jobNotifyTitle(templateType, status, percent)
	body := strings.TrimSpace(summary)
	if body == "" {
		body = fmt.Sprintf("%s · %s", title, jobID)
	}
	// 進度摘要裡若已含 % 就不再重複；否則附上 percent
	if percent > 0 && percent < 100 && !strings.Contains(body, "%") {
		body = fmt.Sprintf("%s · %d%%", body, percent)
	}

	existing, err := s.Repo.FindLatestByJobRef(ctx, ownerUID, jobID)
	now := domain.NowNano()
	if err == nil && existing != nil {
		changed := existing.Title != title || existing.Body != body
		existing.Title = title
		existing.Body = body
		existing.Kind = domain.KindJob
		existing.RefType = domain.RefJob
		existing.RefID = jobID
		// 進度更新保留已讀；只有新的終態結果需要再次提醒。
		markUnread := changed && isTerminalStatus(status)
		if markUnread {
			existing.ReadAt = 0
		}
		// 用 created_at 排序時把最新活動頂到前面
		existing.CreatedAt = now
		return s.Repo.UpdateJobNotification(ctx, existing, markUnread)
	}

	n := &domain.Notification{
		ID: uuid.NewString(), OwnerUID: ownerUID,
		Title: title, Body: body, Kind: domain.KindJob,
		RefType: domain.RefJob, RefID: jobID,
		CreatedAt: now,
	}
	return s.Repo.Insert(ctx, n)
}

func isTerminalStatus(status string) bool {
	return status == "succeeded" || status == "failed" || status == "cancelled"
}

func jobNotifyTitle(templateType, status string, percent int) string {
	name := templateLabelZH(templateType)
	switch status {
	case "succeeded":
		return name + " · 已完成"
	case "failed":
		return name + " · 失敗"
	case "cancelled":
		return name + " · 已取消"
	case "running":
		if percent > 0 {
			return fmt.Sprintf("%s · 進行中 %d%%", name, percent)
		}
		return name + " · 進行中"
	case "queued", "pending":
		return name + " · 已排程"
	default:
		if percent > 0 {
			return fmt.Sprintf("%s · %d%%", name, percent)
		}
		return name + " · 更新"
	}
}

func templateLabelZH(templateType string) string {
	switch templateType {
	case "persona_analyze_account":
		return "人設分析（爬公開貼文）"
	case "persona_analyze_text":
		return "人設分析（文字）"
	case "compose_mimic":
		return "仿寫貼文"
	case "threads_token_renew":
		return "Threads Token 延長"
	case "demo":
		return "Demo 測試任務"
	default:
		if strings.TrimSpace(templateType) == "" {
			return "背景任務"
		}
		return "背景任務"
	}
}
