package main

import (
	"log"
	"net/http"

	"api_es/internal/config"
	"api_es/internal/database"
	"api_es/internal/router"
	"api_es/pkg/logger"

	"go.uber.org/zap"
)

func main() {
	// Загрузка конфигурации приложения из файлов окружения или конфигурационных файлов
	// Конфигурация включает параметры БД, уровень логирования, порт приложения и т.д.
	cfg := config.Load()

	// Инициализация логгера с указанным уровнем логирования и окружением (dev/prod)
	// Логгер будет настроен соответствующим образом для заданного окружения
	logger.Init(cfg.LogLevel, cfg.Environment)
	
	// Получение инстанса логгера для использования во всем приложении
	zapLogger := logger.Get()
	
	// Логирование старта приложения с указанием используемого стека технологий
	zapLogger.Info("Start api_es REST API on stack Golang (gorm, chi) and PostgresDB connect")

	// Инициализация подключения к базе данных PostgreSQL с использованием параметров из конфигурации
	// Возвращается объект gorm.DB для работы с ORM
	db, err := database.NewPostgresConnection(cfg)
	if err != nil {
		// Критическая ошибка подключения к БД - приложение не может работать без БД
		zapLogger.Panic("Failed to connect to database:", zap.Error(err))
	}

	// Получение низкоуровневого объекта *sql.DB из gorm.DB для выполнения операций,
	// не поддерживаемых напрямую gorm (например, Ping)
	sqlDB, err := db.DB()
	if err != nil {
		// Ошибка получения инстанса БД, но приложение может продолжить работу
		zapLogger.Error("failed to get database instance", zap.Error(err))
	}

	// Проверка доступности базы данных через ping-запрос
	// Убеждаемся, что соединение активно и БД отвечает
	if err := sqlDB.Ping(); err != nil {
		zapLogger.Error("database ping failed", zap.Error(err))
	}

	// Успешная проверка соединения с БД
	zapLogger.Info("database ping successful")

	// Настройка маршрутизатора (роутера) для обработки HTTP-запросов
	// Передаем подключение к БД и конфигурацию для инициализации обработчиков
	zapLogger.Info("setup router")
	r := router.SetupRouter(db, cfg)

	// Запуск HTTP-сервера на порту, указанном в конфигурации
	// Сервер начинает прослушивать входящие соединения
	zapLogger.Info("Server starting on port %s", zap.String("AppPort", cfg.AppPort))
	log.Printf("Server starting on port %s", cfg.AppPort)
	
	// Запуск HTTP-сервера с указанным роутером
	// ListenAndServe блокирует выполнение и обрабатывает входящие запросы
	// В случае ошибки запуска сервера, логируем ошибку и завершаем приложение
	if err := http.ListenAndServe(":"+cfg.AppPort, r); err != nil {
		log.Fatal("Failed to start server:", err)
	}
}