package players

import (
	"bytes"
	"encoding/json"
	"fmt"
	"io"
	"mime/multipart"
	"net/http"
	"regexp"
	"strconv"
	"time"
)

// IframeVideoSearchResponse represents the search response from IframeVideo API
type IframeVideoSearchResponse struct {
	Results []struct {
		CID  int    `json:"cid"`
		Path string `json:"path"`
		Type string `json:"type"`
	} `json:"results"`
}

// IframeVideoResponse represents the video response from IframeVideo API
type IframeVideoResponse struct {
	Source string `json:"src"`
}

// IframeVideoPlayer implements the IframeVideo streaming service
type IframeVideoPlayer struct {
	APIHost string
	CDNHost string
	Client  *http.Client
}

// NewIframeVideoPlayer creates a new IframeVideo player instance
func NewIframeVideoPlayer() *IframeVideoPlayer {
	return &IframeVideoPlayer{
		APIHost: "https://iframe.video",
		CDNHost: "https://videoframe.space",
		Client: &http.Client{
			Timeout: 8 * time.Second,
		},
	}
}

// GetStream gets streaming URL by Kinopoisk ID and IMDB ID
func (i *IframeVideoPlayer) GetStream(kinopoiskID, imdbID string) (*StreamResult, error) {
	// First, search for content
	searchResult, err := i.searchContent(kinopoiskID, imdbID)
	if err != nil {
		return nil, fmt.Errorf("search failed: %w", err)
	}

	// Get iframe content to extract token
	token, err := i.extractToken(searchResult.Path)
	if err != nil {
		return nil, fmt.Errorf("token extraction failed: %w", err)
	}

	// Get video URL
	return i.getVideoURL(searchResult.CID, token, searchResult.Type)
}

// searchContent searches for content by Kinopoisk and IMDB IDs
func (i *IframeVideoPlayer) searchContent(kinopoiskID, imdbID string) (*struct {
	CID  int
	Path string
	Type string
}, error) {
	url := fmt.Sprintf("%s/api/v2/search?imdb=%s&kp=%s", i.APIHost, imdbID, kinopoiskID)

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

	req.Header.Set("Accept", "application/json")
	req.Header.Set("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/113.0.0.0 Safari/537.36")

	resp, err := i.Client.Do(req)
	if err != nil {
		return nil, fmt.Errorf("failed to fetch search results: %w", err)
	}
	defer resp.Body.Close()

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

	var searchResp IframeVideoSearchResponse
	if err := json.NewDecoder(resp.Body).Decode(&searchResp); err != nil {
		return nil, fmt.Errorf("failed to decode response: %w", err)
	}

	if len(searchResp.Results) == 0 {
		return nil, fmt.Errorf("content not found")
	}

	result := searchResp.Results[0]
	return &struct {
		CID  int
		Path string
		Type string
	}{
		CID:  result.CID,
		Path: result.Path,
		Type: result.Type,
	}, nil
}

// extractToken extracts token from iframe HTML content
func (i *IframeVideoPlayer) extractToken(path string) (string, error) {
	req, err := http.NewRequest("GET", path, nil)
	if err != nil {
		return "", fmt.Errorf("failed to create request: %w", err)
	}

	// Set headers similar to C# implementation
	req.Header.Set("DNT", "1")
	req.Header.Set("Referer", i.CDNHost+"/")
	req.Header.Set("Sec-Fetch-Dest", "iframe")
	req.Header.Set("Sec-Fetch-Mode", "navigate")
	req.Header.Set("Sec-Fetch-Site", "cross-site")
	req.Header.Set("Upgrade-Insecure-Requests", "1")
	req.Header.Set("sec-ch-ua", `"Google Chrome";v="113", "Chromium";v="113", "Not-A.Brand";v="24"`)
	req.Header.Set("sec-ch-ua-mobile", "?0")
	req.Header.Set("sec-ch-ua-platform", `"Windows"`)
	req.Header.Set("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/113.0.0.0 Safari/537.36")

	resp, err := i.Client.Do(req)
	if err != nil {
		return "", fmt.Errorf("failed to fetch iframe content: %w", err)
	}
	defer resp.Body.Close()

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

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

	// Extract token using regex as in C# implementation
	re := regexp.MustCompile(`\/[^\/]+\/([^\/]+)\/iframe`)
	matches := re.FindStringSubmatch(string(content))
	if len(matches) < 2 {
		return "", fmt.Errorf("token not found in iframe content")
	}

	return matches[1], nil
}

// getVideoURL gets video URL using extracted token
func (i *IframeVideoPlayer) getVideoURL(cid int, token, mediaType string) (*StreamResult, error) {
	// Create multipart form data
	var buf bytes.Buffer
	writer := multipart.NewWriter(&buf)

	writer.WriteField("token", token)
	writer.WriteField("type", mediaType)
	writer.WriteField("season", "")
	writer.WriteField("episode", "")
	writer.WriteField("mobile", "false")
	writer.WriteField("id", strconv.Itoa(cid))
	writer.WriteField("qt", "480")

	contentType := writer.FormDataContentType()
	writer.Close()

	req, err := http.NewRequest("POST", i.CDNHost+"/loadvideo", &buf)
	if err != nil {
		return nil, fmt.Errorf("failed to create request: %w", err)
	}

	req.Header.Set("Content-Type", contentType)
	req.Header.Set("Origin", i.CDNHost)
	req.Header.Set("Referer", i.CDNHost+"/")
	req.Header.Set("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/113.0.0.0 Safari/537.36")

	resp, err := i.Client.Do(req)
	if err != nil {
		return nil, fmt.Errorf("failed to fetch video URL: %w", err)
	}
	defer resp.Body.Close()

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

	var videoResp IframeVideoResponse
	if err := json.NewDecoder(resp.Body).Decode(&videoResp); err != nil {
		return nil, fmt.Errorf("failed to decode video response: %w", err)
	}

	if videoResp.Source == "" {
		return nil, fmt.Errorf("video URL not found")
	}

	return &StreamResult{
		Success:   true,
		StreamURL: videoResp.Source,
		Provider:  "IframeVideo",
		Type:      "direct",
	}, nil
}
