package main

import (
	"fmt"
	"os"
	"strings"

	"github.com/gesellix/bose-soundtouch/pkg/client"
	"github.com/gesellix/bose-soundtouch/pkg/models"
)

// ServiceAvailabilityChecker provides service availability validation for CLI commands
type ServiceAvailabilityChecker struct {
	client                *client.Client
	serviceAvailability   *models.ServiceAvailability
	skipAvailabilityCheck bool
	cached                bool
}

// NewServiceAvailabilityChecker creates a new service availability checker
func NewServiceAvailabilityChecker(client *client.Client) *ServiceAvailabilityChecker {
	skipCheck := os.Getenv("SOUNDTOUCH_SKIP_AVAILABILITY_CHECK") == "true" ||
		os.Getenv("SOUNDTOUCH_SKIP_AVAILABILITY_CHECK") == "1"

	return &ServiceAvailabilityChecker{
		client:                client,
		skipAvailabilityCheck: skipCheck,
		cached:                false,
	}
}

// loadServiceAvailability loads service availability data (cached after first call)
func (sac *ServiceAvailabilityChecker) loadServiceAvailability() {
	if sac.cached {
		return
	}

	if sac.skipAvailabilityCheck {
		// Create a mock availability that allows everything
		sac.serviceAvailability = &models.ServiceAvailability{}
		sac.cached = true

		return
	}

	serviceAvailability, err := sac.client.GetServiceAvailability()
	if err != nil {
		// If availability check fails, warn but don't fail the command
		PrintWarning(fmt.Sprintf("Could not check service availability: %v", err))

		if !sac.skipAvailabilityCheck {
			PrintWarning("Command will proceed without availability validation")
			PrintWarning("Set SOUNDTOUCH_SKIP_AVAILABILITY_CHECK=true to disable these checks")
		}
		// Create empty availability to prevent further errors
		sac.serviceAvailability = &models.ServiceAvailability{}
		sac.cached = true

		return
	}

	sac.serviceAvailability = serviceAvailability
	sac.cached = true
}

// CheckServiceAvailable validates if a service is available and provides user feedback
func (sac *ServiceAvailabilityChecker) CheckServiceAvailable(serviceType models.ServiceType, actionDescription string) bool {
	if sac.skipAvailabilityCheck {
		return true
	}

	sac.loadServiceAvailability()

	// If we couldn't load availability data, allow the operation
	if sac.serviceAvailability == nil || sac.serviceAvailability.Services == nil {
		return true
	}

	if sac.serviceAvailability.IsServiceAvailable(serviceType) {
		return true
	}

	// Service is not available - provide helpful feedback
	serviceName := formatServiceTypeForDisplay(serviceType)
	PrintError(fmt.Sprintf("Cannot %s: %s service is not available", actionDescription, serviceName))

	// Get specific reason if available
	service := sac.serviceAvailability.GetServiceByType(serviceType)
	if service != nil && service.Reason != "" {
		PrintError(fmt.Sprintf("Reason: %s", service.Reason))
	}

	// Provide troubleshooting hints
	sac.provideTroubleshootingHints(serviceType)

	// Suggest alternatives
	sac.suggestAlternatives(serviceType, actionDescription)

	PrintWarning("To bypass this check, set SOUNDTOUCH_SKIP_AVAILABILITY_CHECK=true")

	return false
}

// CheckSourceAvailable validates if a source string corresponds to an available service
func (sac *ServiceAvailabilityChecker) CheckSourceAvailable(source, actionDescription string) bool {
	if sac.skipAvailabilityCheck {
		return true
	}

	serviceType := sourceToServiceType(source)
	if serviceType == "" {
		// Unknown source type, allow it (might be a valid source not in our list)
		return true
	}

	return sac.CheckServiceAvailable(serviceType, actionDescription)
}

// ValidateSpotifyAvailable checks Spotify availability for Spotify-specific operations
func (sac *ServiceAvailabilityChecker) ValidateSpotifyAvailable(actionDescription string) bool {
	return sac.CheckServiceAvailable(models.ServiceTypeSpotify, actionDescription)
}

// ValidateBluetoothAvailable checks Bluetooth availability for Bluetooth operations
func (sac *ServiceAvailabilityChecker) ValidateBluetoothAvailable(actionDescription string) bool {
	return sac.CheckServiceAvailable(models.ServiceTypeBluetooth, actionDescription)
}

// ValidateTuneInAvailable checks TuneIn availability for radio operations
func (sac *ServiceAvailabilityChecker) ValidateTuneInAvailable(actionDescription string) bool {
	return sac.CheckServiceAvailable(models.ServiceTypeTuneIn, actionDescription)
}

// ValidatePandoraAvailable checks Pandora availability for Pandora operations
func (sac *ServiceAvailabilityChecker) ValidatePandoraAvailable(actionDescription string) bool {
	return sac.CheckServiceAvailable(models.ServiceTypePandora, actionDescription)
}

// GetAvailableStreamingServices returns a list of available streaming services for user feedback
func (sac *ServiceAvailabilityChecker) GetAvailableStreamingServices() []string {
	if sac.skipAvailabilityCheck {
		return []string{"All services (availability check disabled)"}
	}

	sac.loadServiceAvailability()

	if sac.serviceAvailability == nil || sac.serviceAvailability.Services == nil {
		return []string{"Unable to determine available services"}
	}

	streamingServices := sac.serviceAvailability.GetStreamingServices()

	var available []string

	for _, service := range streamingServices {
		if service.IsAvailable {
			available = append(available, formatServiceTypeForDisplay(models.ServiceType(service.Type)))
		}
	}

	if len(available) == 0 {
		return []string{"No streaming services currently available"}
	}

	return available
}

// GetAvailableLocalServices returns a list of available local input services
func (sac *ServiceAvailabilityChecker) GetAvailableLocalServices() []string {
	if sac.skipAvailabilityCheck {
		return []string{"All services (availability check disabled)"}
	}

	sac.loadServiceAvailability()

	if sac.serviceAvailability == nil || sac.serviceAvailability.Services == nil {
		return []string{"Unable to determine available services"}
	}

	localServices := sac.serviceAvailability.GetLocalServices()

	var available []string

	for _, service := range localServices {
		if service.IsAvailable {
			available = append(available, formatServiceTypeForDisplay(models.ServiceType(service.Type)))
		}
	}

	if len(available) == 0 {
		return []string{"No local input services currently available"}
	}

	return available
}

// provideTroubleshootingHints provides specific troubleshooting advice based on service type
func (sac *ServiceAvailabilityChecker) provideTroubleshootingHints(serviceType models.ServiceType) {
	switch serviceType {
	case models.ServiceTypeBluetooth:
		PrintWarning("💡 Bluetooth troubleshooting:")
		PrintWarning("   • Check if your device supports Bluetooth audio input")
		PrintWarning("   • Ensure Bluetooth is enabled on the SoundTouch device")
		PrintWarning("   • Try restarting the device")

	case models.ServiceTypeSpotify:
		PrintWarning("💡 Spotify troubleshooting:")
		PrintWarning("   • Ensure you have a Spotify Premium account")
		PrintWarning("   • Check if you're logged in to Spotify on the device")
		PrintWarning("   • Verify your network connection")

	case models.ServiceTypeAirPlay:
		PrintWarning("💡 AirPlay troubleshooting:")
		PrintWarning("   • Ensure your Apple device and SoundTouch are on the same network")
		PrintWarning("   • Check that AirPlay is enabled in device settings")
		PrintWarning("   • Verify network connectivity")

	case models.ServiceTypeAlexa:
		PrintWarning("💡 Alexa troubleshooting:")
		PrintWarning("   • Check if Amazon Alexa is properly configured")
		PrintWarning("   • Ensure the device is connected to your Amazon account")
		PrintWarning("   • Verify internet connectivity")

	case models.ServiceTypeTuneIn:
		PrintWarning("💡 TuneIn troubleshooting:")
		PrintWarning("   • Check internet connectivity")
		PrintWarning("   • Verify the device can access external streaming services")

	case models.ServiceTypePandora:
		PrintWarning("💡 Pandora troubleshooting:")
		PrintWarning("   • Ensure you have a valid Pandora account")
		PrintWarning("   • Check if you're logged in to Pandora on the device")
		PrintWarning("   • Verify internet connectivity")
	}
}

// suggestAlternatives suggests alternative services when the requested one is unavailable
func (sac *ServiceAvailabilityChecker) suggestAlternatives(serviceType models.ServiceType, _ string) {
	if sac.serviceAvailability == nil {
		return
	}

	switch serviceType {
	case models.ServiceTypeSpotify:
		if sac.serviceAvailability.HasTuneIn() {
			PrintWarning("💡 Alternative: TuneIn Radio is available for music streaming")
		}

		if sac.serviceAvailability.HasPandora() {
			PrintWarning("💡 Alternative: Pandora is available for music streaming")
		}

	case models.ServiceTypeBluetooth:
		if sac.serviceAvailability.HasAirPlay() {
			PrintWarning("💡 Alternative: AirPlay is available for wireless audio")
		}

		if sac.serviceAvailability.HasLocalMusic() {
			PrintWarning("💡 Alternative: Local Music Library is available")
		}

	case models.ServiceTypeTuneIn:
		if sac.serviceAvailability.HasSpotify() {
			PrintWarning("💡 Alternative: Spotify is available for music streaming")
		}

		if sac.serviceAvailability.HasPandora() {
			PrintWarning("💡 Alternative: Pandora is available for music streaming")
		}
	}

	// Show all available streaming services as suggestions
	available := sac.GetAvailableStreamingServices()
	if len(available) > 0 && available[0] != "No streaming services currently available" {
		PrintWarning(fmt.Sprintf("💡 Available streaming services: %s", strings.Join(available, ", ")))
	}
}

// sourceToServiceType maps source strings to service types
func sourceToServiceType(source string) models.ServiceType {
	switch strings.ToUpper(source) {
	case "SPOTIFY":
		return models.ServiceTypeSpotify
	case "BLUETOOTH":
		return models.ServiceTypeBluetooth
	case "AIRPLAY":
		return models.ServiceTypeAirPlay
	case "ALEXA":
		return models.ServiceTypeAlexa
	case "AMAZON":
		return models.ServiceTypeAmazon
	case "PANDORA":
		return models.ServiceTypePandora
	case "TUNEIN":
		return models.ServiceTypeTuneIn
	case "DEEZER":
		return models.ServiceTypeDeezer
	case "IHEART", "IHEARTRADIO":
		return models.ServiceTypeIHeart
	case "LOCAL_INTERNET_RADIO":
		return models.ServiceTypeLocalInternetRadio
	case "LOCAL_MUSIC":
		return models.ServiceTypeLocalMusic
	case "BMX":
		return models.ServiceTypeBMX
	case "NOTIFICATION":
		return models.ServiceTypeNotification
	default:
		return ""
	}
}

// formatServiceTypeForDisplay formats service types for user-friendly display
func formatServiceTypeForDisplay(serviceType models.ServiceType) string {
	switch serviceType {
	case models.ServiceTypeSpotify:
		return "Spotify"
	case models.ServiceTypeBluetooth:
		return "Bluetooth"
	case models.ServiceTypeAirPlay:
		return "AirPlay"
	case models.ServiceTypeAlexa:
		return "Amazon Alexa"
	case models.ServiceTypeAmazon:
		return "Amazon Music"
	case models.ServiceTypePandora:
		return "Pandora"
	case models.ServiceTypeTuneIn:
		return "TuneIn Radio"
	case models.ServiceTypeDeezer:
		return "Deezer"
	case models.ServiceTypeIHeart:
		return "iHeartRadio"
	case models.ServiceTypeLocalInternetRadio:
		return "Internet Radio"
	case models.ServiceTypeLocalMusic:
		return "Local Music Library"
	case models.ServiceTypeBMX:
		return "BMX"
	case models.ServiceTypeNotification:
		return "Notifications"
	default:
		return string(serviceType)
	}
}

// PrintServiceAvailabilitySummary prints a summary of available services
func (sac *ServiceAvailabilityChecker) PrintServiceAvailabilitySummary() {
	if sac.skipAvailabilityCheck {
		PrintWarning("Service availability checking is disabled")
		return
	}

	sac.loadServiceAvailability()

	if sac.serviceAvailability == nil || sac.serviceAvailability.Services == nil {
		PrintWarning("Unable to determine service availability")
		return
	}

	fmt.Printf("📊 Service Availability Summary:\n")
	fmt.Printf("   Total services: %d\n", sac.serviceAvailability.GetServiceCount())
	fmt.Printf("   Available: %d\n", sac.serviceAvailability.GetAvailableServiceCount())
	fmt.Printf("   Unavailable: %d\n", sac.serviceAvailability.GetUnavailableServiceCount())

	// Show quick status for popular services
	fmt.Printf("   Popular services:\n")

	popularChecks := []struct {
		check func() bool
		name  string
	}{
		{sac.serviceAvailability.HasSpotify, "Spotify"},
		{sac.serviceAvailability.HasBluetooth, "Bluetooth"},
		{sac.serviceAvailability.HasAirPlay, "AirPlay"},
		{sac.serviceAvailability.HasTuneIn, "TuneIn Radio"},
		{sac.serviceAvailability.HasPandora, "Pandora"},
	}

	for _, check := range popularChecks {
		status := "❌"
		if check.check() {
			status = "✅"
		}

		fmt.Printf("     %s %s\n", status, check.name)
	}

	fmt.Printf("💡 Use 'soundtouch-cli sources list' to see configured sources\n")
}
