package integrations

import (
	"context"
	"fmt"
	"os/exec"
	"strings"
	"time"
)

// OnlyOfficeNextcloudHandler enables/disables OnlyOffice document editing in Nextcloud via occ.
type OnlyOfficeNextcloudHandler struct{}

func (h *OnlyOfficeNextcloudHandler) Apply(ac *ApplyContext) error {
	jwtSecret := ac.ProviderEnv["JWT_SECRET"]
	if jwtSecret == "" {
		ac.Logger.Printf("[ERROR] [integrations] OnlyOffice-Nextcloud apply: JWT_SECRET not set")
		return fmt.Errorf("OnlyOffice JWT_SECRET nincs beállítva")
	}

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

	publicURL := fmt.Sprintf("https://%s.%s", subdomain, ac.Domain)
	internalURL := "http://onlyoffice:80"

	// Install and configure OnlyOffice app in Nextcloud
	commands := []struct {
		args    []string
		tolerate string // substring in output to tolerate as success
	}{
		{
			args:     []string{"docker", "exec", "-u", "www-data", "nextcloud", "php", "occ", "app:install", "onlyoffice"},
			tolerate: "already installed",
		},
		{
			args: []string{"docker", "exec", "-u", "www-data", "nextcloud", "php", "occ", "app:enable", "onlyoffice"},
		},
		{
			args: []string{"docker", "exec", "-u", "www-data", "nextcloud", "php", "occ", "config:app:set", "onlyoffice", "DocumentServerUrl", "--value=" + publicURL},
		},
		{
			args: []string{"docker", "exec", "-u", "www-data", "nextcloud", "php", "occ", "config:app:set", "onlyoffice", "DocumentServerInternalUrl", "--value=" + internalURL},
		},
		{
			args: []string{"docker", "exec", "-u", "www-data", "nextcloud", "php", "occ", "config:app:set", "onlyoffice", "jwt_secret", "--value=" + jwtSecret},
		},
		{
			// StorageUrl: tells OO Document Server where to reach Nextcloud internally for file callbacks.
			// Trailing slash is critical — NC's OO connector does string replacement of the server URL
			// (which ends with /) with StorageUrl. Without trailing slash, "/apps/..." merges into hostname.
			args: []string{"docker", "exec", "-u", "www-data", "nextcloud", "php", "occ", "config:app:set", "onlyoffice", "StorageUrl", "--value=http://nextcloud/"},
		},
		{
			// Add internal hostname to trusted_domains so OO Document Server callbacks
			// (arriving with Host: nextcloud) are not rejected by Nextcloud.
			args: []string{"docker", "exec", "-u", "www-data", "nextcloud", "php", "occ", "config:system:set", "trusted_domains", "10", "--value=nextcloud"},
		},
	}

	for _, cmd := range commands {
		ctx, cancel := context.WithTimeout(context.Background(), 60*time.Second)
		c := exec.CommandContext(ctx, cmd.args[0], cmd.args[1:]...)
		out, err := c.CombinedOutput()
		cancel()
		if err != nil {
			if cmd.tolerate != "" && strings.Contains(string(out), cmd.tolerate) {
				ac.Logger.Printf("[DEBUG] [integrations] Nextcloud occ: tolerated — %s", strings.TrimSpace(string(out)))
				continue
			}
			ac.Logger.Printf("[ERROR] [integrations] OnlyOffice-Nextcloud apply: occ %s failed: %v", cmd.args[len(cmd.args)-1], err)
			return fmt.Errorf("occ parancs sikertelen (%s): %v (kimenet: %s)", cmd.args[len(cmd.args)-1], err, strings.TrimSpace(string(out)))
		}
		ac.Logger.Printf("[DEBUG] [integrations] Nextcloud occ %s: ok", strings.Join(cmd.args[7:], " "))
	}

	ac.Logger.Printf("[INFO] [integrations] OnlyOffice integration applied to Nextcloud")
	return nil
}

func (h *OnlyOfficeNextcloudHandler) Revoke(ac *ApplyContext) error {
	ctx, cancel := context.WithTimeout(context.Background(), 60*time.Second)
	defer cancel()

	cmd := exec.CommandContext(ctx, "docker", "exec", "-u", "www-data", "nextcloud", "php", "occ", "app:disable", "onlyoffice")
	out, err := cmd.CombinedOutput()
	if err != nil {
		outStr := string(out)
		// Tolerate container not running or app not enabled
		if strings.Contains(err.Error(), "No such container") ||
			strings.Contains(outStr, "not enabled") ||
			strings.Contains(outStr, "not installed") {
			ac.Logger.Printf("[DEBUG] [integrations] Nextcloud occ app:disable skipped — %s", strings.TrimSpace(outStr))
			return nil
		}
		ac.Logger.Printf("[ERROR] [integrations] OnlyOffice-Nextcloud revoke: occ app:disable failed: %v", err)
		return fmt.Errorf("occ app:disable sikertelen: %v (kimenet: %s)", err, strings.TrimSpace(outStr))
	}

	ac.Logger.Printf("[INFO] [integrations] OnlyOffice integration revoked from Nextcloud")
	return nil
}
