package qcclient

import (
	"encoding/json"
	"fmt"
	"strconv"
	"strings"
)

type APIResponse[T any] struct {
	Status string `json:"status"`
	Data   T      `json:"data"`
}

type APIError struct {
	Status  string         `json:"status"`
	Message string         `json:"message"`
	Code    string         `json:"code"`
	Details map[string]any `json:"details,omitempty"`
}

type Template struct {
	ID                    int64                  `json:"id"`
	Name                  string                 `json:"name"`
	Description           string                 `json:"description"`
	Locale                string                 `json:"locale"`
	ThumbnailURL          string                 `json:"thumbnailUrl"`
	TemplatePreviewURL    string                 `json:"templatePreviewUrl"`
	Type                  string                 `json:"type"`
	PaletteReady          Boolish                `json:"paletteReady"`
	GlobalColors          map[string]any         `json:"globalColors"`
	TextsWithGlobalColors map[string]any         `json:"textsWithGlobalColors"`
	TemplateHeadings      []TemplateHeading      `json:"templateHeadings,omitempty"`
	Raw                   map[string]interface{} `json:"-"`
}

type Boolish bool

func (b Boolish) Bool() bool {
	return bool(b)
}

func (b Boolish) MarshalJSON() ([]byte, error) {
	return json.Marshal(bool(b))
}

func (b *Boolish) UnmarshalJSON(data []byte) error {
	trimmed := strings.TrimSpace(string(data))
	if trimmed == "" || strings.EqualFold(trimmed, "null") {
		*b = false
		return nil
	}

	var boolVal bool
	if err := json.Unmarshal(data, &boolVal); err == nil {
		*b = Boolish(boolVal)
		return nil
	}

	var numVal float64
	if err := json.Unmarshal(data, &numVal); err == nil {
		*b = Boolish(numVal != 0)
		return nil
	}

	var stringVal string
	if err := json.Unmarshal(data, &stringVal); err == nil {
		parsed, err := parseBoolishString(stringVal)
		if err != nil {
			return err
		}
		*b = Boolish(parsed)
		return nil
	}

	return fmt.Errorf("unsupported boolish value: %s", trimmed)
}

func parseBoolishString(v string) (bool, error) {
	normalized := strings.ToLower(strings.TrimSpace(v))
	switch normalized {
	case "", "0", "false", "f", "no", "n", "off":
		return false, nil
	case "1", "true", "t", "yes", "y", "on":
		return true, nil
	}

	numeric, err := strconv.ParseFloat(normalized, 64)
	if err == nil {
		return numeric != 0, nil
	}

	return false, fmt.Errorf("unsupported boolish string value: %q", v)
}

type TemplateHeading struct {
	TranslationKey string `json:"translationKey"`
}

type GenerateContentRequest struct {
	TemplateID         int64          `json:"templateId"`
	GlobalData         map[string]any `json:"globalData"`
	Empty              bool           `json:"empty"`
	ToneOfVoice        string         `json:"toneOfVoice,omitempty"`
	TargetAudience     string         `json:"targetAudience,omitempty"`
	CustomTemplateData map[string]any `json:"customTemplateData,omitempty"`
}

type GenerateContentData map[string]map[string]any

type CreateSiteRequest struct {
	TemplateID int64             `json:"templateId"`
	GlobalData map[string]any    `json:"globalData"`
	Content    CreateSiteContent `json:"content"`
}

type CreateSiteContent struct {
	AIData map[string]map[string]any `json:"aiData"`
}

type CreateSiteResponseData struct {
	Status string `json:"status"`
	JobID  int64  `json:"jobId"`
}

type JobStatusResult struct {
	SiteID     int64  `json:"siteId"`
	PreviewURL string `json:"previewUrl"`
}

type JobStatusData struct {
	JobID     int64           `json:"jobId"`
	Status    string          `json:"status"`
	CreatedAt int64           `json:"createdAt"`
	Result    JobStatusResult `json:"result"`
}

type SiteEditorLoginData struct {
	LoginURL string `json:"loginUrl"`
}
