package android

import (
	"fmt"
	"io"
	"os"
	"path/filepath"
	"strings"
)

// Fetcher handles template copying
type Fetcher struct{}

// NewFetcher creates a new template fetcher
func NewFetcher() *Fetcher {
	return &Fetcher{}
}

// FetchTemplate copies a local template based on platform and layout
// Returns the path to the copied template directory
func (f *Fetcher) FetchTemplate(platform, layoutTemplate, buildID string) (string, error) {
	// Base templates are in ./templates (committed to repo)
	baseTemplatesDir := "./templates"
	// Build workspaces are in ./storage/workspaces (runtime data)
	workspaceDir := "./storage/workspaces"

	// Map layout_template to directory name
	templateName, err := f.getTemplateName(platform, layoutTemplate)
	if err != nil {
		return "", err
	}

	// Build full path to source template
	sourcePath := filepath.Join(baseTemplatesDir, platform, templateName)

	// Check if template directory exists
	if _, err := os.Stat(sourcePath); os.IsNotExist(err) {
		return "", fmt.Errorf("template not found: %s", sourcePath)
	}

	// Copy template to build directory
	destPath := filepath.Join(workspaceDir, buildID)
	if err := f.copyDir(sourcePath, destPath); err != nil {
		return "", fmt.Errorf("failed to copy template: %w", err)
	}

	return destPath, nil
}

// getTemplateName maps layout_template values to directory names
func (f *Fetcher) getTemplateName(platform, layoutTemplate string) (string, error) {
	if platform != "android-webview" {
		return "", fmt.Errorf("unsupported platform: %s (only 'android-webview' is supported)", platform)
	}

	// Map Appy's layout_template values to template directory names
	templateMap := map[string]string{
		"app_bar_drawer": "drawer",
		"app_bar_tabs":   "tabs",
		"app_bar":        "appbar",
		"blank":          "blank",
	}

	name, ok := templateMap[layoutTemplate]
	if !ok {
		return "", fmt.Errorf("unknown layout_template: %s (valid options: app_bar_drawer, app_bar_tabs, app_bar, blank)", layoutTemplate)
	}

	return name, nil
}

// copyDir recursively copies a directory from src to dst
func (f *Fetcher) copyDir(src, dst string) error {
	// Get source directory info
	srcInfo, err := os.Stat(src)
	if err != nil {
		return err
	}

	// Create destination directory
	if err := os.MkdirAll(dst, srcInfo.Mode()); err != nil {
		return err
	}

	// Read source directory entries
	entries, err := os.ReadDir(src)
	if err != nil {
		return err
	}

	// Copy each entry
	for _, entry := range entries {
		srcPath := filepath.Join(src, entry.Name())
		dstPath := filepath.Join(dst, entry.Name())

		// Skip hidden files and build artifacts
		if strings.HasPrefix(entry.Name(), ".") ||
			entry.Name() == "build" ||
			entry.Name() == "local.properties" {
			continue
		}

		if entry.IsDir() {
			// Recursively copy subdirectory
			if err := f.copyDir(srcPath, dstPath); err != nil {
				return err
			}
		} else {
			// Copy file
			if err := f.copyFile(srcPath, dstPath); err != nil {
				return err
			}
		}
	}

	return nil
}

// copyFile copies a single file from src to dst
func (f *Fetcher) copyFile(src, dst string) error {
	// Open source file
	srcFile, err := os.Open(src)
	if err != nil {
		return err
	}
	defer srcFile.Close()

	// Get source file info for permissions
	srcInfo, err := srcFile.Stat()
	if err != nil {
		return err
	}

	// Create destination file
	dstFile, err := os.OpenFile(dst, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, srcInfo.Mode())
	if err != nil {
		return err
	}
	defer dstFile.Close()

	// Copy contents
	_, err = io.Copy(dstFile, srcFile)
	return err
}
