package integrations

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

// OnlyOfficeFileBrowserHandler enables/disables OnlyOffice document editing in FileBrowser Quantum.
type OnlyOfficeFileBrowserHandler struct{}

func (h *OnlyOfficeFileBrowserHandler) Apply(ac *ApplyContext) error {
	jwtSecret := ac.ProviderEnv["JWT_SECRET"]
	if jwtSecret == "" {
		ac.Logger.Printf("[ERROR] [integrations] OnlyOffice-FileBrowser apply: JWT_SECRET not set")
		return fmt.Errorf("OnlyOffice JWT_SECRET nincs beállítva — telepítsd újra az alkalmazást")
	}

	subdomain := ac.ProviderEnv["SUBDOMAIN"]
	if subdomain == "" && ac.ProviderMeta != nil {
		subdomain = ac.ProviderMeta.Subdomain
	}
	if subdomain == "" {
		ac.Logger.Printf("[ERROR] [integrations] OnlyOffice-FileBrowser apply: subdomain unknown")
		return fmt.Errorf("OnlyOffice aldomain nem ismert")
	}

	configPath := filepath.Join(ac.StacksDir, "filebrowser", "config.yaml")
	officeURL := fmt.Sprintf("https://%s.%s", subdomain, ac.Domain)

	configData, err := os.ReadFile(configPath)
	if err != nil {
		ac.Logger.Printf("[ERROR] [integrations] OnlyOffice-FileBrowser apply: %v", err)
		return fmt.Errorf("FileBrowser config olvasási hiba: %w", err)
	}

	// Remove any existing integrations section, then append the new one
	configStr := removeIntegrationsSection(string(configData))

	internalURL := "http://onlyoffice:80"

	integrationsBlock := fmt.Sprintf("integrations:\n  office:\n    url: %q\n    internalUrl: %q\n    secret: %q\n    viewOnly: false\n",
		officeURL, internalURL, jwtSecret)

	configStr = strings.TrimRight(configStr, "\n") + "\n" + integrationsBlock

	// Atomic write
	tmpPath := configPath + ".tmp"
	if err := os.WriteFile(tmpPath, []byte(configStr), 0644); err != nil {
		ac.Logger.Printf("[ERROR] [integrations] OnlyOffice-FileBrowser apply: %v", err)
		return fmt.Errorf("config írási hiba: %w", err)
	}
	if err := os.Rename(tmpPath, configPath); err != nil {
		_ = os.Remove(tmpPath)
		ac.Logger.Printf("[ERROR] [integrations] OnlyOffice-FileBrowser apply: %v", err)
		return fmt.Errorf("config átnevezési hiba: %w", err)
	}

	ac.Logger.Printf("[INFO] [integrations] FileBrowser config updated with OnlyOffice integration")
	return ac.RestartStack("filebrowser")
}

func (h *OnlyOfficeFileBrowserHandler) Revoke(ac *ApplyContext) error {
	configPath := filepath.Join(ac.StacksDir, "filebrowser", "config.yaml")
	ac.Logger.Printf("[DEBUG] [integrations] OnlyOfficeFileBrowser.Revoke: configPath=%s", configPath)

	configData, err := os.ReadFile(configPath)
	if err != nil {
		if os.IsNotExist(err) {
			return nil
		}
		ac.Logger.Printf("[ERROR] [integrations] OnlyOffice-FileBrowser revoke: %v", err)
		return fmt.Errorf("config olvasási hiba: %w", err)
	}

	cleaned := removeIntegrationsSection(string(configData))
	hadIntegrations := cleaned != string(configData)
	ac.Logger.Printf("[DEBUG] [integrations] OnlyOfficeFileBrowser.Revoke: integrationsSectionFound=%v", hadIntegrations)
	if !hadIntegrations {
		return nil // no integrations section, nothing to remove
	}

	tmpPath := configPath + ".tmp"
	if err := os.WriteFile(tmpPath, []byte(cleaned), 0644); err != nil {
		ac.Logger.Printf("[ERROR] [integrations] OnlyOffice-FileBrowser revoke: %v", err)
		return fmt.Errorf("config írási hiba: %w", err)
	}
	if err := os.Rename(tmpPath, configPath); err != nil {
		_ = os.Remove(tmpPath)
		ac.Logger.Printf("[ERROR] [integrations] OnlyOffice-FileBrowser revoke: %v", err)
		return fmt.Errorf("config átnevezési hiba: %w", err)
	}

	ac.Logger.Printf("[INFO] [integrations] FileBrowser config cleaned — OnlyOffice integration removed")
	return ac.RestartStack("filebrowser")
}

// removeIntegrationsSection strips the integrations: YAML block from a config string.
// It removes from the line starting with "integrations:" to the next unindented key or EOF.
func removeIntegrationsSection(config string) string {
	lines := strings.Split(config, "\n")
	var result []string
	inBlock := false
	for _, line := range lines {
		if strings.HasPrefix(line, "integrations:") {
			inBlock = true
			continue
		}
		if inBlock {
			trimmed := strings.TrimRight(line, " \t\r")
			if trimmed == "" {
				continue // skip blank lines within block
			}
			if line[0] != ' ' && line[0] != '\t' {
				// New top-level key — end of integrations block
				inBlock = false
				result = append(result, line)
			}
			// else: still inside indented block, skip
			continue
		}
		result = append(result, line)
	}
	return strings.Join(result, "\n")
}
