package database

import (
	"fmt"
	"log"
	"os"
	"time"

	"gorm.io/driver/postgres"
	"gorm.io/gorm"
	"gorm.io/gorm/logger"

	"sensor-server/internal/models"
)

var DB *gorm.DB

// InitDatabase 데이터베이스 초기화
func InitDatabase() error {
	dsn := fmt.Sprintf("host=%s user=%s password=%s dbname=%s port=%s sslmode=disable",
		getEnv("DB_HOST", "localhost"),
		getEnv("DB_USER", "postgres"),
		getEnv("DB_PASSWORD", "password"),
		getEnv("DB_NAME", "sensor_db"),
		getEnv("DB_PORT", "5432"),
	)

	var err error
	DB, err = gorm.Open(postgres.Open(dsn), &gorm.Config{
		Logger: logger.Default.LogMode(logger.Info),
	})

	if err != nil {
		return fmt.Errorf("failed to connect to database: %v", err)
	}

	// 안전한 마이그레이션 수행
	err = safeMigrate()
	if err != nil {
		return fmt.Errorf("failed to migrate database: %v", err)
	}

	// Connection pool 설정
	sqlDB, err := DB.DB()
	if err != nil {
		return fmt.Errorf("failed to get underlying sql.DB: %v", err)
	}

	sqlDB.SetMaxIdleConns(10)
	sqlDB.SetMaxOpenConns(100)
	sqlDB.SetConnMaxLifetime(time.Hour)

	log.Println("Database initialized successfully")
	return nil
}

// safeMigrate 안전한 마이그레이션 수행
func safeMigrate() error {
	// 기존 제약조건 확인 및 정리
	if err := cleanupConstraints(); err != nil {
		log.Printf("Warning: failed to cleanup constraints: %v", err)
	}

	// AutoMigrate 수행
	return DB.AutoMigrate(&models.SensorReading{}, &models.Device{})
}

// cleanupConstraints 기존 제약조건 정리
func cleanupConstraints() error {
	// devices 테이블의 device_id unique 제약조건 확인
	var count int64
	err := DB.Raw(`
		SELECT COUNT(*) FROM information_schema.table_constraints 
		WHERE table_name = 'devices' 
		AND constraint_name = 'uni_devices_device_id'
	`).Scan(&count).Error
	
	if err != nil {
		return err
	}

	// 제약조건이 존재하면 삭제
	if count > 0 {
		err = DB.Exec(`ALTER TABLE devices DROP CONSTRAINT IF EXISTS uni_devices_device_id`).Error
		if err != nil {
			return err
		}
		log.Println("Cleaned up existing constraint: uni_devices_device_id")
	}

	return nil
}

// GetDB 데이터베이스 인스턴스 반환
func GetDB() *gorm.DB {
	return DB
}

// getEnv 환경변수 조회 (기본값 포함)
func getEnv(key, defaultValue string) string {
	if value := os.Getenv(key); value != "" {
		return value
	}
	return defaultValue
} 