package elevenlabs

import (
	"context"
	"encoding/json"
	"fmt"
	"net/http"
)

const (
	// DefaultVoiceDesignModel is the default model for voice design.
	DefaultVoiceDesignModel = "eleven_multilingual_ttv_v2"

	// DefaultGuidanceScale balances prompt adherence with audio quality.
	DefaultGuidanceScale = 5.0

	// DefaultLoudness is the default volume level.
	DefaultLoudness = 0.5
)

// DesignVoice generates voice previews from a text description.
// Returns typically 3 voice previews to choose from.
func (c *Client) DesignVoice(ctx context.Context, req VoiceDesignRequest) (*VoiceDesignResponse, error) {
	if req.VoiceDescription == "" {
		return nil, fmt.Errorf("%w: voice description is required", ErrInvalidConfig)
	}
	if len(req.VoiceDescription) < 20 || len(req.VoiceDescription) > 1000 {
		return nil, fmt.Errorf("%w: voice description must be 20-1000 characters", ErrInvalidConfig)
	}

	// Set defaults
	if req.ModelID == "" {
		req.ModelID = DefaultVoiceDesignModel
	}
	if req.GuidanceScale == 0 {
		req.GuidanceScale = DefaultGuidanceScale
	}
	if req.Loudness == 0 {
		req.Loudness = DefaultLoudness
	}

	// If no text provided, enable auto-generation
	if req.Text == "" {
		req.AutoGenerateText = true
	}

	respBody, err := c.doRequest(ctx, http.MethodPost, "/text-to-voice/design", req)
	if err != nil {
		return nil, fmt.Errorf("design voice: %w", err)
	}

	var resp VoiceDesignResponse
	if err := json.Unmarshal(respBody, &resp); err != nil {
		return nil, fmt.Errorf("unmarshal voice design response: %w", err)
	}

	return &resp, nil
}

// SaveDesignedVoice saves a voice preview as a permanent voice.
// The GeneratedVoiceID comes from a VoicePreview returned by DesignVoice.
func (c *Client) SaveDesignedVoice(ctx context.Context, req SaveVoiceRequest) (*SaveVoiceResponse, error) {
	if req.VoiceName == "" {
		return nil, fmt.Errorf("%w: voice name is required", ErrInvalidConfig)
	}
	if req.GeneratedVoiceID == "" {
		return nil, fmt.Errorf("%w: generated voice ID is required", ErrInvalidConfig)
	}

	respBody, err := c.doRequest(ctx, http.MethodPost, "/text-to-voice/create-voice-from-preview", req)
	if err != nil {
		return nil, fmt.Errorf("save designed voice: %w", err)
	}

	var resp SaveVoiceResponse
	if err := json.Unmarshal(respBody, &resp); err != nil {
		return nil, fmt.Errorf("unmarshal save voice response: %w", err)
	}

	return &resp, nil
}

// DeleteVoice removes a voice from the account.
func (c *Client) DeleteVoice(ctx context.Context, voiceID string) error {
	if voiceID == "" {
		return fmt.Errorf("%w: voice ID is required", ErrInvalidConfig)
	}

	path := fmt.Sprintf("/voices/%s", voiceID)
	_, err := c.doRequest(ctx, http.MethodDelete, path, nil)
	if err != nil {
		return fmt.Errorf("delete voice: %w", err)
	}

	return nil
}
