package services

import (
	"encoding/json"
	"errors"
	"fmt"
	"image"
	_ "image/jpeg"
	_ "image/png"
	"math"
	"net/http"
	"strings"
	"time"

	"fotbal-club/internal/models"

	"github.com/muesli/clusters"
	"github.com/muesli/kmeans"
)

type FACRService struct {
	baseURL    string
	httpClient *http.Client
}

type FACRClubSearchResponse struct {
	Query   string `json:"query"`
	Count   int    `json:"count"`
	Results []struct {
		Name     string `json:"name"`
		ClubID   string `json:"club_id"`
		ClubType string `json:"club_type"`
		LogoURL  string `json:"logo_url"`
		Category string `json:"category"`
	} `json:"results"`
}

// NewFACRService creates a new FACR service instance
func NewFACRService(baseURL string) *FACRService {
	return &FACRService{
		baseURL: strings.TrimSuffix(baseURL, "/"),
		httpClient: &http.Client{
			Timeout: 30 * time.Second,
		},
	}
}

// SearchClubs searches for clubs by name
func (s *FACRService) SearchClubs(query string) ([]models.ClubSearchResult, error) {
	if query == "" {
		return nil, errors.New("search query cannot be empty")
	}

	url := fmt.Sprintf("%s/club/search?q=%s", s.baseURL, query)
	resp, err := s.httpClient.Get(url)
	if err != nil {
		return nil, fmt.Errorf("error making request: %v", err)
	}
	defer resp.Body.Close()

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

	var result FACRClubSearchResponse
	if err := json.NewDecoder(resp.Body).Decode(&result); err != nil {
		return nil, fmt.Errorf("error decoding response: %v", err)
	}

	var clubs []models.ClubSearchResult
	for _, club := range result.Results {
		clubs = append(clubs, models.ClubSearchResult{
			ID:       club.ClubID,
			Name:     club.Name,
			Type:     club.ClubType,
			LogoURL:  club.LogoURL,
			Category: club.Category,
		})
	}

	return clubs, nil
}

// extractColorsFromLogo extracts dominant colors from a logo image
func (s *FACRService) extractColorsFromLogo(logoURL string) (string, string, string, error) {
	resp, err := s.httpClient.Get(logoURL)
	if err != nil {
		return "", "", "", fmt.Errorf("error downloading logo: %v", err)
	}
	defer resp.Body.Close()

	img, _, err := image.Decode(resp.Body)
	if err != nil {
		return "", "", "", fmt.Errorf("error decoding image: %v", err)
	}

	bounds := img.Bounds()
	var points []clusters.Observation

	// Sample pixels (every 10th pixel for performance)
	for y := bounds.Min.Y; y < bounds.Max.Y; y += 10 {
		for x := bounds.Min.X; x < bounds.Max.X; x += 10 {
			r, g, b, a := img.At(x, y).RGBA()
			if a > 0x7FFF { // Skip transparent pixels
				// Convert to float64 slice and create a new observation
				point := []float64{
					float64(r >> 8),
					float64(g >> 8),
					float64(b >> 8),
				}
				points = append(points, clusters.Coordinates(point))
			}
		}
	}

	if len(points) == 0 {
		return "#1E40AF", "#F59E0B", "#1F2937", nil
	}

	// Find 3 dominant colors using k-means
	km := kmeans.New()
	clusters, err := km.Partition(points, 3) // Find 3 dominant colors
	if err != nil {
		return "", "", "", fmt.Errorf("error in k-means clustering: %v", err)
	}

	// Sort clusters by size (number of points in each cluster)
	for i := 0; i < len(clusters); i++ {
		for j := i + 1; j < len(clusters); j++ {
			if len(clusters[j].Observations) > len(clusters[i].Observations) {
				clusters[i], clusters[j] = clusters[j], clusters[i]
			}
		}
	}

	// Get primary and secondary colors
	primary := clusters[0].Center
	secondary := clusters[1%len(clusters)].Center

	// Calculate text color based on brightness
	brightness := (0.299*primary[0] + 0.587*primary[1] + 0.114*primary[2]) / 255.0
	textColor := "#000000"
	if brightness < 0.5 {
		textColor = "#FFFFFF"
	}

	return rgbToHex(primary), rgbToHex(secondary), textColor, nil
}

// rgbToHex converts RGB values to hex color
func rgbToHex(rgb []float64) string {
	return fmt.Sprintf("#%02X%02X%02X",
		uint8(math.Round(rgb[0])),
		uint8(math.Round(rgb[1])),
		uint8(math.Round(rgb[2])),
	)
}

// GetClubDetails fetches detailed information about a club
func (s *FACRService) GetClubDetails(clubID string) (*models.ClubInfo, error) {
	if clubID == "" {
		return nil, errors.New("club ID cannot be empty")
	}

	url := fmt.Sprintf("%s/club/football/%s", s.baseURL, clubID)
	req, err := http.NewRequest("GET", url, nil)
	if err != nil {
		return nil, fmt.Errorf("error creating request: %v", err)
	}

	resp, err := s.httpClient.Do(req)
	if err != nil {
		return nil, fmt.Errorf("error making request: %v", err)
	}
	defer resp.Body.Close()

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

	var club struct {
		Name     string `json:"name"`
		ClubID   string `json:"club_id"`
		LogoURL  string `json:"logo_url"`
		Category string `json:"category"`
	}

	if err := json.NewDecoder(resp.Body).Decode(&club); err != nil {
		return nil, fmt.Errorf("error decoding response: %v", err)
	}

	// Extract colors from logo if available
	var primaryColor, secondaryColor, textColor string
	var errExtract error

	if club.LogoURL != "" {
		primaryColor, secondaryColor, textColor, errExtract = s.extractColorsFromLogo(club.LogoURL)
		if errExtract != nil {
			// Log the error but continue with default colors
			fmt.Printf("Warning: Could not extract colors from logo: %v\n", errExtract)
		}
	}

	// Set default colors if extraction failed or wasn't attempted
	if primaryColor == "" {
		primaryColor = "#1E40AF"   // Blue
		secondaryColor = "#F59E0B" // Amber
		textColor = "#1F2937"      // Gray-800
	}

	return &models.ClubInfo{
		FACRClubID:     club.ClubID,
		Name:           club.Name,
		ShortName:      club.Name, // Using name as fallback for short name
		LogoURL:        club.LogoURL,
		PrimaryColor:   primaryColor,
		SecondaryColor: secondaryColor,
		TextColor:      textColor,
	}, nil
}
