//go:build darwin

package installer

import (
	"fmt"
	"os"
	"os/exec"
	"path/filepath"

	"gitgud.io/mike/mpv-manager/internal/assets"
	"gitgud.io/mike/mpv-manager/pkg/constants"
)

// CreateMacOSWebUIShortcutWithOutput creates a macOS app bundle for the Web UI
func CreateMacOSWebUIShortcutWithOutput(cr *CommandRunner) error {
	execPath, err := os.Executable()
	if err != nil {
		return fmt.Errorf("failed to get executable path: %w", err)
	}

	cr.outputChan <- "Creating Web UI app bundle..."

	appsDir := "/Applications"
	appPath := filepath.Join(appsDir, "MPV Manager.app")

	if _, err := os.Stat(appPath); err == nil {
		cr.outputChan <- "⚠ App bundle already exists: " + appPath
		return nil
	}

	contentsDir := filepath.Join(appPath, "Contents")
	macosDir := filepath.Join(contentsDir, "MacOS")
	resourcesDir := filepath.Join(contentsDir, "Resources")

	for _, dir := range []string{contentsDir, macosDir, resourcesDir} {
		if err := os.MkdirAll(dir, 0755); err != nil {
			return fmt.Errorf("failed to create directory: %w", err)
		}
	}

	wrapperScript := `#!/bin/bash
cd "$(dirname "$0")"
"` + execPath + `" -m web
`
	wrapperPath := filepath.Join(macosDir, "mpv-manager")
	if err := os.WriteFile(wrapperPath, []byte(wrapperScript), 0755); err != nil {
		return fmt.Errorf("failed to write wrapper script: %w", err)
	}

	infoPlistContent := `<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
    <key>CFBundleExecutable</key>
    <string>mpv-manager</string>
    <key>CFBundleIdentifier</key>
    <string>com.mpv.manager</string>
    <key>CFBundleName</key>
    <string>MPV Manager</string>
    <key>CFBundleDisplayName</key>
    <string>MPV Manager</string>
    <key>CFBundleVersion</key>
    <string>0.1.0</string>
    <key>CFBundlePackageType</key>
    <string>APPL</string>
    <key>CFBundleIconFile</key>
    <string>AppIcon</string>
</dict>
</plist>
`
	infoPlistPath := filepath.Join(contentsDir, "Info.plist")
	if err := os.WriteFile(infoPlistPath, []byte(infoPlistContent), 0644); err != nil {
		return fmt.Errorf("failed to write Info.plist: %w", err)
	}

	// Create macOS installer instance to install icon
	mi := &MacOSInstaller{}
	if err := mi.InstallIconWithOutput(cr); err != nil {
		cr.outputChan <- "Warning: Failed to prepare icon: " + err.Error()
	}

	// Copy icon to Resources
	homeDir, _ := os.UserHomeDir()
	icnsPath := filepath.Join(homeDir, constants.MacOSTempIconDir, constants.MacOSIconFileName)
	if _, err := os.Stat(icnsPath); err == nil {
		destIconPath := filepath.Join(resourcesDir, "AppIcon.icns")
		if data, err := os.ReadFile(icnsPath); err == nil {
			if err := os.WriteFile(destIconPath, data, 0644); err == nil {
				cr.outputChan <- "✓ Icon installed: " + destIconPath
			} else {
				cr.outputChan <- "Warning: Failed to copy icon: " + err.Error()
			}
		}
	} else {
		// Fallback: use PNG directly (some macOS versions don't support iconutil)
		pngPath := filepath.Join(homeDir, constants.MacOSTempIconDir, "icon-128.png")
		if _, err := os.Stat(pngPath); err == nil {
			destIconPath := filepath.Join(resourcesDir, "AppIcon.png")
			if data, err := os.ReadFile(pngPath); err == nil {
				if err := os.WriteFile(destIconPath, data, 0644); err == nil {
					cr.outputChan <- "✓ Icon installed (PNG fallback): " + destIconPath
				}
			}
		}
	}

	// Extract the macOS uninstall script to ~/.config/mpv directory
	configDir := filepath.Join(homeDir, ".config", "mpv")
	if err := assets.ExtractUninstallMacOSSh(configDir); err != nil {
		cr.outputChan <- "Warning: Failed to extract uninstall script: " + err.Error()
	} else {
		cr.outputChan <- "✓ Uninstall script installed: " + filepath.Join(configDir, "uninstall-macos.sh")
	}

	cr.outputChan <- "✓ App bundle created: " + appPath
	cr.outputChan <- "Note: You may need to allow app in System Preferences > Security & Privacy."

	return nil
}

// CreateWebUIShortcutWithOutput is the method wrapper for CreateMacOSWebUIShortcutWithOutput
func (mi *MacOSInstaller) CreateWebUIShortcutWithOutput(cr *CommandRunner) error {
	return CreateMacOSWebUIShortcutWithOutput(cr)
}

// ConvertPNGToICNS converts a PNG file to ICNS format using iconutil
// Creates an iconset with multiple sizes and converts to ICNS
func ConvertPNGToICNS(pngPath, icnsPath string) error {
	// Check if iconutil is available
	if _, err := exec.LookPath("iconutil"); err != nil {
		return fmt.Errorf("iconutil not available on this system")
	}

	// Create temporary iconset directory
	iconsetDir := pngPath + ".iconset"
	if err := os.MkdirAll(iconsetDir, 0755); err != nil {
		return fmt.Errorf("failed to create iconset directory: %w", err)
	}
	defer os.RemoveAll(iconsetDir)

	// Required sizes for macOS iconset
	sizes := []string{
		"16", "32", "64", "128", "256", "512",
	}

	// Create icons for each size using sips (built into macOS)
	for _, size := range sizes {
		// Create regular and retina (2x) versions
		for _, scale := range []string{"1", "2"} {
			var targetSize string
			var filename string

			if scale == "2" {
				targetSize = size + "x" + size
				filename = fmt.Sprintf("icon_%sx%s.png", size, size)
			} else {
				// For retina, we use 2x the size
				baseSize := size
				if baseSize == "16" || baseSize == "32" || baseSize == "64" || baseSize == "128" || baseSize == "256" || baseSize == "512" {
					baseSizeInt := 0
					fmt.Sscanf(baseSize, "%d", &baseSizeInt)
					baseSizeInt *= 2
					targetSize = fmt.Sprintf("%dx%d", baseSizeInt, baseSizeInt)
					filename = fmt.Sprintf("icon_%s@2x.png", size)
				}
			}

			// Use sips to resize the PNG
			if scale == "2" {
				baseSizeInt := 0
				fmt.Sscanf(size, "%d", &baseSizeInt)
				baseSizeInt *= 2
				targetSize = fmt.Sprintf("%dx%d", baseSizeInt, baseSizeInt)
				filename = fmt.Sprintf("icon_%s@2x.png", size)
			}

			outPath := filepath.Join(iconsetDir, filename)
			cmd := exec.Command("sips", "-z", targetSize, targetSize, pngPath, "--out", outPath)
			if output, err := cmd.CombinedOutput(); err != nil {
				// Log warning but continue - some sizes may fail
				fmt.Printf("Warning: Failed to create %s: %v\nOutput: %s\n", filename, err, string(output))
			}
		}
	}

	// Convert iconset to ICNS using iconutil
	cmd := exec.Command("iconutil", "-c", "icns", iconsetDir, "-o", icnsPath)
	if output, err := cmd.CombinedOutput(); err != nil {
		return fmt.Errorf("iconutil failed: %w\nOutput: %s", err, string(output))
	}

	return nil
}

// InstallIconWithOutput installs the icon for macOS app bundles
func (mi *MacOSInstaller) InstallIconWithOutput(cr *CommandRunner) error {
	homeDir, err := os.UserHomeDir()
	if err != nil {
		return fmt.Errorf("failed to get home directory: %w", err)
	}

	// Create temp icon directory
	tempIconDir := filepath.Join(homeDir, constants.MacOSTempIconDir)
	if err := os.MkdirAll(tempIconDir, 0755); err != nil {
		return fmt.Errorf("failed to create temp icon directory: %w", err)
	}

	pngPath := filepath.Join(tempIconDir, "icon-128.png")
	icnsPath := filepath.Join(tempIconDir, constants.MacOSIconFileName)

	// Check if ICNS already exists
	if _, err := os.Stat(icnsPath); err == nil {
		cr.outputChan <- "Icon already converted: " + icnsPath
		return nil
	}

	cr.outputChan <- "Converting icon to ICNS format..."

	// Extract PNG from embedded assets
	pngData, err := assets.ReadPNGIcon()
	if err != nil {
		return fmt.Errorf("failed to read icon from assets: %w", err)
	}

	if err := os.WriteFile(pngPath, pngData, 0644); err != nil {
		return fmt.Errorf("failed to write PNG file: %w", err)
	}

	// Convert PNG to ICNS
	if err := ConvertPNGToICNS(pngPath, icnsPath); err != nil {
		// iconutil may not be available on all macOS versions
		// Fall back to using PNG directly in app bundle
		cr.outputChan <- "Warning: Could not convert to ICNS, will use PNG as fallback: " + err.Error()
		return nil
	}

	cr.outputChan <- "✓ Icon converted: " + icnsPath
	return nil
}
