package templatesvc

import (
	"context"
	"encoding/json"
	"fmt"
	"sort"
	"strings"

	"qctextbuilder/internal/domain"
	"qctextbuilder/internal/qcclient"
	"qctextbuilder/internal/store"
)

type Service struct {
	qc            qcclient.Client
	templateStore store.TemplateStore
	manifestStore store.ManifestStore
}

type TemplateDetail struct {
	Template *domain.Template         `json:"template"`
	Manifest *domain.TemplateManifest `json:"manifest,omitempty"`
	Fields   []domain.TemplateField   `json:"fields"`
}

func New(qc qcclient.Client, templateStore store.TemplateStore, manifestStore store.ManifestStore) *Service {
	return &Service{
		qc:            qc,
		templateStore: templateStore,
		manifestStore: manifestStore,
	}
}

func (s *Service) SyncAITemplates(ctx context.Context) ([]domain.Template, error) {
	templates, err := s.qc.ListAITemplates(ctx)
	if err != nil {
		return nil, err
	}

	out := make([]domain.Template, 0, len(templates))
	for _, t := range templates {
		raw, _ := json.Marshal(t)
		out = append(out, domain.Template{
			ID:                 t.ID,
			Name:               t.Name,
			Description:        t.Description,
			Locale:             strings.ToUpper(t.Locale),
			ThumbnailURL:       t.ThumbnailURL,
			TemplatePreviewURL: t.TemplatePreviewURL,
			Type:               t.Type,
			PaletteReady:       t.PaletteReady.Bool(),
			RawJSON:            raw,
			IsAITemplate:       strings.EqualFold(t.Type, "ai"),
			ManifestStatus:     "missing",
		})
	}

	if err := s.templateStore.UpsertTemplates(ctx, out); err != nil {
		return nil, err
	}
	return out, nil
}

func (s *Service) ListTemplates(ctx context.Context) ([]domain.Template, error) {
	templates, err := s.templateStore.ListTemplates(ctx)
	if err != nil {
		return nil, fmt.Errorf("list templates: %w", err)
	}

	sort.Slice(templates, func(i, j int) bool {
		if templates[i].Name == templates[j].Name {
			return templates[i].ID < templates[j].ID
		}
		return templates[i].Name < templates[j].Name
	})
	return templates, nil
}

func (s *Service) GetTemplateDetail(ctx context.Context, templateID int64) (*TemplateDetail, error) {
	template, err := s.templateStore.GetTemplateByID(ctx, templateID)
	if err != nil {
		return nil, fmt.Errorf("get template: %w", err)
	}

	detail := &TemplateDetail{
		Template: template,
		Fields:   []domain.TemplateField{},
	}

	manifest, err := s.manifestStore.GetActiveManifestByTemplateID(ctx, templateID)
	if err != nil {
		if isNotFoundErr(err) {
			return detail, nil
		}
		return nil, fmt.Errorf("get active manifest: %w", err)
	}

	fields, err := s.manifestStore.ListFieldsByManifestID(ctx, manifest.ID)
	if err != nil {
		return nil, fmt.Errorf("list fields: %w", err)
	}
	sort.Slice(fields, func(i, j int) bool {
		if fields[i].DisplayOrder == fields[j].DisplayOrder {
			return fields[i].Path < fields[j].Path
		}
		return fields[i].DisplayOrder < fields[j].DisplayOrder
	})

	detail.Manifest = manifest
	detail.Fields = fields
	return detail, nil
}

func isNotFoundErr(err error) bool {
	return strings.Contains(strings.ToLower(strings.TrimSpace(err.Error())), "not found")
}
