package config

import (
	"encoding/json"
	"fmt"
	"os"
	"os/exec"
	"path/filepath"
)

// Config структура конфигурации
type Config struct {
	GoService struct {
		Port   int    `json:"port"`
		Prefix string `json:"prefix"`
	} `json:"goService"`
	Redis struct {
		Host     string `json:"host"`
		Port     int    `json:"port"`
		Password string `json:"password"`
	} `json:"redis"`
	MongoDB struct {
		Host     string `json:"host"`
		Port     int    `json:"port"`
		Username string `json:"username"`
		Password string `json:"password"`
		Database string `json:"database"`
	} `json:"mongodb"`
}

var instance *Config

// Load загружает конфигурацию из PHP файла
func Load() (*Config, error) {
	if instance != nil {
		return instance, nil
	}

	// Определяем путь к корню проекта
	rootDir := os.Getenv("SHM_ROOT_DIR")
	if rootDir == "" {
		// Пытаемся определить автоматически (относительно текущей директории)
		// services/go -> ../../
		currentDir, err := os.Getwd()
		if err != nil {
			return nil, fmt.Errorf("failed to get current directory: %w", err)
		}

		// Проверяем, находимся ли мы в services/go
		if filepath.Base(currentDir) == "go" {
			rootDir = filepath.Join(currentDir, "..", "..")
		} else {
			// Если запускаем из другой директории, используем текущую
			rootDir = currentDir
		}
	}

	configPath := filepath.Join(rootDir, "config", "config.php")

	// Получаем абсолютный путь
	absConfigPath, err := filepath.Abs(configPath)
	if err != nil {
		return nil, fmt.Errorf("failed to get absolute path: %w", err)
	}

	// Проверяем существование файла
	if _, err := os.Stat(absConfigPath); os.IsNotExist(err) {
		return nil, fmt.Errorf("config file not found: %s", absConfigPath)
	}

	// Создаем PHP скрипт для экспорта конфига в JSON
	// Используем переменную для безопасной передачи пути
	phpScript := fmt.Sprintf(`
		<?php
		$configPath = %q;
		$config = require $configPath;
		echo json_encode($config, JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE);
	`, absConfigPath)

	// Пытаемся найти PHP в системе
	phpCmd := "php"
	if phpPath := os.Getenv("PHP_PATH"); phpPath != "" {
		phpCmd = phpPath
	} else {
		// Пробуем найти php в PATH
		if _, err := exec.LookPath("php"); err != nil {
			// Пробуем альтернативные пути
			alternatives := []string{"php8.1", "php8.2", "php8.3", "/usr/bin/php", "/usr/local/bin/php"}
			for _, alt := range alternatives {
				if _, err := exec.LookPath(alt); err == nil {
					phpCmd = alt
					break
				}
			}
		}
	}

	// Выполняем PHP скрипт
	cmd := exec.Command(phpCmd, "-r", phpScript)
	output, err := cmd.Output()
	if err != nil {
		if exitError, ok := err.(*exec.ExitError); ok {
			return nil, fmt.Errorf("failed to execute PHP script: %w (stderr: %s)", err, string(exitError.Stderr))
		}
		return nil, fmt.Errorf("failed to execute PHP script: %w", err)
	}

	// Парсим JSON
	var config Config
	if err := json.Unmarshal(output, &config); err != nil {
		return nil, fmt.Errorf("failed to parse config JSON: %w", err)
	}

	instance = &config
	return instance, nil
}

// Get возвращает загруженную конфигурацию
func Get() *Config {
	if instance == nil {
		cfg, err := Load()
		if err != nil {
			panic(fmt.Sprintf("Failed to load config: %v", err))
		}
		return cfg
	}
	return instance
}

// Reload перезагружает конфигурацию
func Reload() error {
	instance = nil
	_, err := Load()
	return err
}
