package adultemp

import (
	"context"
	"fmt"
	"io"
	"net/http"
	"net/http/cookiejar"
	"net/url"
	"time"

	"golang.org/x/net/publicsuffix"
)

// Client handles HTTP requests to Adult Empire
type Client struct {
	httpClient *http.Client
	baseURL    string
	userAgent  string
}

// NewClient creates a new Adult Empire client
func NewClient() (*Client, error) {
	// Create cookie jar for session management
	jar, err := cookiejar.New(&cookiejar.Options{
		PublicSuffixList: publicsuffix.List,
	})
	if err != nil {
		return nil, fmt.Errorf("failed to create cookie jar: %w", err)
	}

	client := &http.Client{
		Jar:     jar,
		Timeout: 30 * time.Second,
		CheckRedirect: func(req *http.Request, via []*http.Request) error {
			// Allow up to 10 redirects
			if len(via) >= 10 {
				return fmt.Errorf("stopped after 10 redirects")
			}
			return nil
		},
	}

	c := &Client{
		httpClient: client,
		baseURL:    "https://www.adultempire.com",
		userAgent:  "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36",
	}

	// Set age confirmation cookie by default
	if err := c.setAgeConfirmation(); err != nil {
		return nil, fmt.Errorf("failed to set age confirmation: %w", err)
	}

	return c, nil
}

// setAgeConfirmation sets the age confirmation cookie required to view Adult Empire content
func (c *Client) setAgeConfirmation() error {
	u, err := url.Parse(c.baseURL)
	if err != nil {
		return err
	}

	cookies := []*http.Cookie{
		{
			Name:   "ageConfirmed",
			Value:  "1",
			Domain: ".adultempire.com",
			Path:   "/",
		},
	}

	c.httpClient.Jar.SetCookies(u, cookies)
	return nil
}

// SetAuthToken sets the authentication token for Adult Empire
// etoken is the session cookie from an authenticated Adult Empire session
func (c *Client) SetAuthToken(etoken string) error {
	u, err := url.Parse(c.baseURL)
	if err != nil {
		return err
	}

	// Set the etoken cookie
	cookies := []*http.Cookie{
		{
			Name:   "etoken",
			Value:  etoken,
			Domain: ".adultempire.com",
			Path:   "/",
		},
		{
			Name:   "ageConfirmed",
			Value:  "1",
			Domain: ".adultempire.com",
			Path:   "/",
		},
	}

	c.httpClient.Jar.SetCookies(u, cookies)
	return nil
}

// Get performs a GET request to the specified path
func (c *Client) Get(ctx context.Context, path string) ([]byte, error) {
	fullURL := c.baseURL + path

	req, err := http.NewRequestWithContext(ctx, "GET", fullURL, nil)
	if err != nil {
		return nil, fmt.Errorf("failed to create request: %w", err)
	}

	req.Header.Set("User-Agent", c.userAgent)
	req.Header.Set("Accept", "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8")
	req.Header.Set("Accept-Language", "en-US,en;q=0.5")

	resp, err := c.httpClient.Do(req)
	if err != nil {
		return nil, fmt.Errorf("request failed: %w", err)
	}
	defer resp.Body.Close()

	if resp.StatusCode != http.StatusOK {
		return nil, fmt.Errorf("unexpected status code: %d", resp.StatusCode)
	}

	body, err := io.ReadAll(resp.Body)
	if err != nil {
		return nil, fmt.Errorf("failed to read response body: %w", err)
	}

	return body, nil
}

// SearchScenes searches for scenes by query
func (c *Client) SearchScenes(ctx context.Context, query string) ([]byte, error) {
	// Adult Empire search URL format
	searchPath := fmt.Sprintf("/dvd/search?q=%s", url.QueryEscape(query))
	return c.Get(ctx, searchPath)
}

// SearchPerformers searches for performers by name
func (c *Client) SearchPerformers(ctx context.Context, name string) ([]byte, error) {
	// Adult Empire performer search
	searchPath := fmt.Sprintf("/performer/search?q=%s", url.QueryEscape(name))
	return c.Get(ctx, searchPath)
}

// GetSceneByURL fetches a scene page by its URL
func (c *Client) GetSceneByURL(ctx context.Context, sceneURL string) ([]byte, error) {
	// Parse the URL to get just the path
	u, err := url.Parse(sceneURL)
	if err != nil {
		return nil, fmt.Errorf("invalid URL: %w", err)
	}

	// If it's a full URL, use the path; otherwise use as-is
	path := sceneURL
	if u.Host != "" {
		path = u.Path
		if u.RawQuery != "" {
			path += "?" + u.RawQuery
		}
	}

	return c.Get(ctx, path)
}

// GetPerformerByURL fetches a performer page by its URL
func (c *Client) GetPerformerByURL(ctx context.Context, performerURL string) ([]byte, error) {
	u, err := url.Parse(performerURL)
	if err != nil {
		return nil, fmt.Errorf("invalid URL: %w", err)
	}

	path := performerURL
	if u.Host != "" {
		path = u.Path
		if u.RawQuery != "" {
			path += "?" + u.RawQuery
		}
	}

	return c.Get(ctx, path)
}
