package main

import (
	"crm-go/internal/handlers"
	"crm-go/internal/middleware"
	"crm-go/internal/storage"
	"crm-go/services"
	"log"
	"net/http"
	"os"
	"path/filepath"
	"strings"
	"time"
)

func main() {
	// 获取存储模式，默认使用MySQL
	storageMode := os.Getenv("STORAGE_MODE")
	if storageMode == "" {
		storageMode = "mysql" // 默认使用MySQL
	}

	var customerStorage storage.CustomerStorage
	var followUpStorage storage.FollowUpStorage
	var trialPeriodStorage storage.TrialPeriodStorage

	if storageMode == "mysql" {
		// 初始化MySQL数据库连接
		dbConfig := storage.GetDBConfigFromEnv()
		if err := storage.InitDB(dbConfig); err != nil {
			log.Fatalf("Failed to initialize database: %v", err)
		}
		defer storage.CloseDB()

		// 使用MySQL存储
		customerStorage = storage.NewMySQLCustomerStorage()
		followUpStorage = storage.NewMySQLFollowUpStorage()
		trialPeriodStorage = storage.NewMySQLTrialPeriodStorage()
		log.Println("✅ Using MySQL storage")
	} else {
		// 使用JSON文件存储（向后兼容）
		customerStorage = storage.NewCustomerStorage("./data/customers.json")
		followUpStorage = storage.NewFollowUpStorage("./data/followups.json")
		trialPeriodStorage = storage.NewTrialPeriodStorage("./data/trial_periods.json")
		log.Println("✅ Using JSON file storage")
	}

	// Get Feishu webhook URL from environment variable
	feishuWebhook := "https://open.feishu.cn/open-apis/bot/v2/hook/d75c14ad-d782-489e-8a99-81b511ee4abd"

	// Initialize handlers
	customerHandler := handlers.NewCustomerHandler(customerStorage, feishuWebhook)
	followUpHandler := handlers.NewFollowUpHandler(followUpStorage, customerStorage, feishuWebhook)
	trialPeriodHandler := handlers.NewTrialPeriodHandler(trialPeriodStorage, customerStorage, feishuWebhook)
	authHandler := handlers.NewAuthHandler()

	// Start notification checker in background
	go func() {
		ticker := time.NewTicker(1 * time.Minute)
		defer ticker.Stop()
		for range ticker.C {
			if err := followUpHandler.CheckAndSendNotifications(); err != nil {
				log.Printf("Error checking notifications: %v", err)
			}
		}
	}()

	// Start trial expiry checker in background
	// Workday schedule: Monday-Friday, 11:00 AM and 5:00 PM
	trialChecker := services.NewTrialExpiryChecker(feishuWebhook)
	go func() {
		// Helper function to check and send trial expiry notifications
		checkTrialExpiry := func() {
			trialPeriods, err := trialPeriodStorage.GetAllTrialPeriods()
			if err != nil {
				log.Printf("Error loading trial periods for expiry check: %v", err)
				return
			}

			customers, err := customerStorage.GetAllCustomers()
			if err != nil {
				log.Printf("Error loading customers for trial check: %v", err)
				return
			}

			// Create customer name map
			customersMap := make(map[string]string)
			for _, c := range customers {
				customersMap[c.ID] = c.CustomerName
			}

			// Convert to services.TrialPeriod type
			serviceTrialPeriods := make([]services.TrialPeriod, len(trialPeriods))
			for i, tp := range trialPeriods {
				serviceTrialPeriods[i] = services.TrialPeriod{
					ID:           tp.ID,
					CustomerName: tp.CustomerName,
					StartTime:    tp.StartTime,
					EndTime:      tp.EndTime,
					CreatedAt:    tp.CreatedAt,
				}
			}

			if err := trialChecker.CheckTrialPeriodsAndNotify(serviceTrialPeriods, customersMap); err != nil {
				log.Printf("Error checking trial expiry: %v", err)
			}
		}

		// Helper function to check if it's a workday (Monday-Friday)
		isWorkday := func(t time.Time) bool {
			weekday := t.Weekday()
			return weekday >= time.Monday && weekday <= time.Friday
		}

		// Helper function to check if current time matches notification time (11:00 or 17:00)
		isNotificationTime := func(t time.Time) bool {
			hour := t.Hour()
			minute := t.Minute()
			// Check for 11:00 AM or 5:00 PM (17:00)
			return (hour == 11 || hour == 17) && minute == 0
		}

		// Track last notification time to prevent duplicate sends
		var lastNotificationTime time.Time

		// Check immediately on startup (only on workdays)
		now := time.Now()
		if isWorkday(now) {
			log.Println("Trial expiry checker: Running initial check on startup...")
			checkTrialExpiry()
			lastNotificationTime = now
		}

		// Check every minute for scheduled notification times
		// Workdays: Monday-Friday, 11:00 AM and 5:00 PM
		ticker := time.NewTicker(1 * time.Minute)
		defer ticker.Stop()
		for range ticker.C {
			now := time.Now()

			// Only send on workdays at 11:00 AM or 5:00 PM
			if isWorkday(now) && isNotificationTime(now) {
				// Ensure we don't send duplicate notifications for the same time slot
				if lastNotificationTime.Hour() != now.Hour() ||
					lastNotificationTime.Day() != now.Day() ||
					lastNotificationTime.Month() != now.Month() {
					log.Printf("Trial expiry checker: Sending scheduled notification at %s", now.Format("2006-01-02 15:04"))
					checkTrialExpiry()
					lastNotificationTime = now
				}
			}
		}
	}()

	// Enable CORS manually
	corsHandler := func(h http.Handler) http.Handler {
		return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
			w.Header().Set("Access-Control-Allow-Origin", "*")
			w.Header().Set("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE, OPTIONS")
			w.Header().Set("Access-Control-Allow-Headers", "Content-Type, Authorization")

			if r.Method == "OPTIONS" {
				w.WriteHeader(http.StatusOK)
				return
			}

			h.ServeHTTP(w, r)
		})
	}

	// Auth routes
	http.HandleFunc("/api/login", authHandler.Login)

	// Set up routes using standard http
	http.HandleFunc("/api/customers", func(w http.ResponseWriter, r *http.Request) {
		switch r.Method {
		case "GET":
			customerHandler.GetCustomers(w, r)
		case "POST":
			customerHandler.CreateCustomer(w, r)
		default:
			http.Error(w, "Method not allowed", http.StatusMethodNotAllowed)
		}
	})

	http.HandleFunc("/api/customers/", func(w http.ResponseWriter, r *http.Request) {
		path := r.URL.Path

		// Handle import endpoint
		if path == "/api/customers/import" {
			if r.Method == "POST" {
				customerHandler.ImportCustomers(w, r)
				return
			}
		}

		// Handle customer ID endpoints
		if strings.HasPrefix(path, "/api/customers/") && path != "/api/customers/" {
			// Extract customer ID from URL
			id := strings.TrimPrefix(path, "/api/customers/")

			// Remove query parameters if any
			if idx := strings.Index(id, "?"); idx != -1 {
				id = id[:idx]
			}

			if id != "" {
				if r.Method == "GET" {
					customerHandler.GetCustomerByID(w, r)
					return
				}
				if r.Method == "PUT" {
					customerHandler.UpdateCustomer(w, r)
					return
				}
				if r.Method == "DELETE" {
					customerHandler.DeleteCustomer(w, r)
					return
				}
			}
		}

		http.NotFound(w, r)
	})

	// Follow-up routes
	http.HandleFunc("/api/followups", func(w http.ResponseWriter, r *http.Request) {
		switch r.Method {
		case "GET":
			followUpHandler.GetFollowUps(w, r)
		case "POST":
			followUpHandler.CreateFollowUp(w, r)
		default:
			http.Error(w, "Method not allowed", http.StatusMethodNotAllowed)
		}
	})

	http.HandleFunc("/api/followups/", func(w http.ResponseWriter, r *http.Request) {
		path := r.URL.Path

		// Handle follow-up ID endpoints
		if strings.HasPrefix(path, "/api/followups/") && path != "/api/followups/" {
			// Extract follow-up ID from URL
			id := strings.TrimPrefix(path, "/api/followups/")

			// Remove query parameters if any
			if idx := strings.Index(id, "?"); idx != -1 {
				id = id[:idx]
			}

			if id != "" {
				if r.Method == "GET" {
					followUpHandler.GetFollowUpByID(w, r)
					return
				}
				if r.Method == "PUT" {
					followUpHandler.UpdateFollowUp(w, r)
					return
				}
				if r.Method == "DELETE" {
					followUpHandler.DeleteFollowUp(w, r)
					return
				}
			}
		}

		http.NotFound(w, r)
	})

	// Customer list endpoint for follow-up form
	http.HandleFunc("/api/customers/list", func(w http.ResponseWriter, r *http.Request) {
		if r.Method == "GET" {
			followUpHandler.GetCustomerList(w, r)
		} else {
			http.Error(w, "Method not allowed", http.StatusMethodNotAllowed)
		}
	})

	// Trial period routes
	http.HandleFunc("/api/trial-periods", func(w http.ResponseWriter, r *http.Request) {
		switch r.Method {
		case "GET":
			trialPeriodHandler.GetTrialPeriodsByCustomer(w, r)
		case "POST":
			trialPeriodHandler.CreateTrialPeriod(w, r)
		default:
			http.Error(w, "Method not allowed", http.StatusMethodNotAllowed)
		}
	})

	// Get all trial periods
	http.HandleFunc("/api/trial-periods/all", func(w http.ResponseWriter, r *http.Request) {
		if r.Method == "GET" {
			trialPeriodHandler.GetAllTrialPeriods(w, r)
		} else {
			http.Error(w, "Method not allowed", http.StatusMethodNotAllowed)
		}
	})

	// Get unique customer list from trial periods
	http.HandleFunc("/api/trial-customers/list", func(w http.ResponseWriter, r *http.Request) {
		if r.Method == "GET" {
			trialPeriodHandler.GetTrialCustomerList(w, r)
		} else {
			http.Error(w, "Method not allowed", http.StatusMethodNotAllowed)
		}
	})

	http.HandleFunc("/api/trial-periods/", func(w http.ResponseWriter, r *http.Request) {
		path := r.URL.Path

		if strings.HasPrefix(path, "/api/trial-periods/") && path != "/api/trial-periods/" {
			id := strings.TrimPrefix(path, "/api/trial-periods/")
			if idx := strings.Index(id, "?"); idx != -1 {
				id = id[:idx]
			}

			if id != "" {
				if r.Method == "PUT" {
					trialPeriodHandler.UpdateTrialPeriod(w, r)
					return
				}
				if r.Method == "DELETE" {
					trialPeriodHandler.DeleteTrialPeriod(w, r)
					return
				}
			}
		}

		http.NotFound(w, r)
	})

	// Serve static files for the frontend
	staticDir := "./frontend"
	if _, err := os.Stat(staticDir); os.IsNotExist(err) {
		// Create basic frontend directory if it doesn't exist
		os.MkdirAll(staticDir, 0755)
	}

	// Serve static files
	http.Handle("/static/", http.StripPrefix("/static/", http.FileServer(http.Dir("./frontend"))))

	// Serve index page
	http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
		http.ServeFile(w, r, filepath.Join("./frontend", "index.html"))
	})

	// Assemble final handler chain: DefaultServeMux -> AuthMiddleware -> CorsHandler
	finalHandler := middleware.AuthMiddleware(http.DefaultServeMux)

	port := os.Getenv("PORT")
	if port == "" {
		port = "8081"
	}
	addr := ":" + port
	log.Println("Server starting on " + addr)
	log.Fatal(http.ListenAndServe(addr, corsHandler(finalHandler)))
}
