package main

import (
	"bytes"
	"encoding/json"
	"fmt"
	"html/template"
	"io"
	"log"
	"net/http"
	"os"
	"strings"
	"sync"
	"time"
)

// Configuration holds all website configuration
type Config struct {
	CompanyName      string
	KVK              string
	Email            string
	Phone            string
	Street           string
	PostalCode       string
	Village          string
	Domain           string
	Port             string
	TelegramBotToken string
	TelegramChatID   string
}

// PageData holds data for template rendering
type PageData struct {
	Config
	Title          string
	CurrentPage    string
	CurrentYear    int
	ErrorMessage   string
	SuccessMessage string
	FormData       ContactForm
	AboutName      string
	AgeYears       int
	SonAgeYears    int
}

// ContactForm holds form data
type ContactForm struct {
	Name     string
	Email    string
	Phone    string
	Computer string
	Service  string
	Message  string
}

// Server holds the application state
type Server struct {
	config    Config
	templates *template.Template
}

// Rate limiting
var (
	mu                 sync.Mutex
	lastSubmissionTime = make(map[string]time.Time)
	submissionCooldown = 5 * time.Minute
)

// getEnv returns environment variable or default value
func getEnv(key, defaultValue string) string {
	if value := os.Getenv(key); value != "" {
		return value
	}
	return defaultValue
}

// NewServer creates a new server instance
func NewServer() *Server {
	// Configuration - can be overridden with environment variables
	config := Config{
		CompanyName:      getEnv("COMPANY_NAME", "Hogeland Linux"),
		KVK:              getEnv("KVK", "12345678"), // Replace with actual KVK number
		Email:            getEnv("EMAIL", "info@hogelandlinux.nl"),
		Phone:            getEnv("PHONE", "+31 6 12345678"),
		Street:           getEnv("STREET", "Voorstraat 123"),
		PostalCode:       getEnv("POSTAL_CODE", "9967 AA"),
		Village:          getEnv("VILLAGE", "Eenrum"),
		Domain:           getEnv("DOMAIN", "hogelandlinux.nl"), // Replace with actual domain
		Port:             ":" + getEnv("PORT", "8080"),
		TelegramBotToken: getEnv("TELEGRAM_BOT_TOKEN", ""), // Set this in environment
		TelegramChatID:   getEnv("TELEGRAM_CHAT_ID", ""),   // Set this in environment
	}

	// Parse templates with error handling
	templates, err := template.ParseGlob("templates/*.html")
	if err != nil {
		log.Fatalf("Failed to parse templates: %v", err)
	}

	return &Server{
		config:    config,
		templates: templates,
	}
}

// createPageData creates PageData with the given title and current page
func (s *Server) createPageData(title, currentPage string) PageData {
	return PageData{
		Config:      s.config,
		Title:       title,
		CurrentPage: currentPage,
		CurrentYear: time.Now().Year(),
	}
}

// renderTemplate renders a template with error handling
func (s *Server) renderTemplate(w http.ResponseWriter, templateName string, data PageData) {
	if err := s.templates.ExecuteTemplate(w, templateName, data); err != nil {
		log.Printf("Template execution error: %v", err)
		http.Error(w, "Internal Server Error", http.StatusInternalServerError)
	}
}

// homeHandler handles the home page
func (s *Server) homeHandler(w http.ResponseWriter, r *http.Request) {
	data := s.createPageData("Linux-migratieservice - uw computer nieuw leven geven", "home")
	s.renderTemplate(w, "index.html", data)
}

// contactHandler handles the contact page
func (s *Server) contactHandler(w http.ResponseWriter, r *http.Request) {
	data := s.createPageData("Contact - "+s.config.CompanyName, "contact")

	if r.Method == "POST" {
		s.handleContactForm(w, r, &data)
		return
	}

	s.renderTemplate(w, "contact.html", data)
}

// handleContactForm processes the contact form submission
func (s *Server) handleContactForm(w http.ResponseWriter, r *http.Request, data *PageData) {
	// Get client IP for rate limiting
	ip := getClientIP(r)

	// Check rate limiting
	mu.Lock()
	if lastTime, exists := lastSubmissionTime[ip]; exists {
		if time.Since(lastTime) < submissionCooldown {
			mu.Unlock()
			data.ErrorMessage = "U hebt recent al een bericht verstuurd. Probeer het over een paar minuten opnieuw."
			s.renderTemplate(w, "contact.html", *data)
			return
		}
	}
	mu.Unlock()

	// Parse form data
	err := r.ParseForm()
	if err != nil {
		log.Printf("Error parsing form: %v", err)
		data.ErrorMessage = "Er is een fout opgetreden bij het verwerken van uw bericht."
		s.renderTemplate(w, "contact.html", *data)
		return
	}

	// Extract form data
	form := ContactForm{
		Name:     strings.TrimSpace(r.FormValue("name")),
		Email:    strings.TrimSpace(r.FormValue("email")),
		Phone:    strings.TrimSpace(r.FormValue("phone")),
		Computer: strings.TrimSpace(r.FormValue("computer")),
		Service:  strings.TrimSpace(r.FormValue("service")),
		Message:  strings.TrimSpace(r.FormValue("message")),
	}

	// Store form data for re-rendering on error
	data.FormData = form

	// Validate required fields
	if form.Name == "" || form.Email == "" || form.Message == "" {
		data.ErrorMessage = "Vul alle verplichte velden in (naam, e-mail, bericht)."
		s.renderTemplate(w, "contact.html", *data)
		return
	}

	// Send to Telegram if configured
	if s.config.TelegramBotToken != "" && s.config.TelegramChatID != "" {
		err := s.sendToTelegram(form)
		if err != nil {
			log.Printf("Error sending message to Telegram: %v", err)
			data.ErrorMessage = "Er is een fout opgetreden bij het versturen van uw bericht. Probeer het later opnieuw."
			s.renderTemplate(w, "contact.html", *data)
			return
		}
	}

	// Update last submission time on success
	mu.Lock()
	lastSubmissionTime[ip] = time.Now()
	mu.Unlock()

	// On success, render success message
	data.SuccessMessage = "Bedankt voor uw bericht! We nemen zo snel mogelijk contact met u op."
	data.FormData = ContactForm{} // Clear form data
	s.renderTemplate(w, "contact.html", *data)
}

// sendToTelegram sends the contact form data to Telegram
func (s *Server) sendToTelegram(form ContactForm) error {
	// Format message
	message := fmt.Sprintf(
		"🔔 Nieuw contactformulier\n\n"+
			"👤 *Naam:* %s\n"+
			"📧 *Email:* %s\n"+
			"📞 *Telefoon:* %s\n"+
			"💻 *Computer:* %s\n"+
			"🛠️ *Service:* %s\n\n"+
			"💬 *Bericht:*\n%s",
		escapeMarkdown(form.Name),
		escapeMarkdown(form.Email),
		escapeMarkdown(form.Phone),
		escapeMarkdown(form.Computer),
		escapeMarkdown(form.Service),
		escapeMarkdown(form.Message),
	)

	// Prepare Telegram API request
	telegramURL := fmt.Sprintf("https://api.telegram.org/bot%s/sendMessage", s.config.TelegramBotToken)

	payload := map[string]interface{}{
		"chat_id":    s.config.TelegramChatID,
		"text":       message,
		"parse_mode": "Markdown",
	}

	jsonData, err := json.Marshal(payload)
	if err != nil {
		return fmt.Errorf("failed to marshal JSON: %v", err)
	}

	// Send HTTP request
	resp, err := http.Post(telegramURL, "application/json", bytes.NewBuffer(jsonData))
	if err != nil {
		return fmt.Errorf("failed to send HTTP request: %v", err)
	}
	defer resp.Body.Close()

	if resp.StatusCode != http.StatusOK {
		bodyBytes, _ := io.ReadAll(resp.Body)
		return fmt.Errorf("Telegram API error: %s, Status Code: %d", string(bodyBytes), resp.StatusCode)
	}

	return nil
}

// escapeMarkdown escapes special characters for Telegram Markdown
func escapeMarkdown(text string) string {
	if text == "" {
		return "N/A"
	}
	// Escape special Markdown characters
	replacer := strings.NewReplacer(
		"*", "\\*",
		"_", "\\_",
		"`", "\\`",
		"[", "\\[",
		"]", "\\]",
		"(", "\\(",
		")", "\\)",
		"~", "\\~",
		">", "\\>",
		"#", "\\#",
		"+", "\\+",
		"-", "\\-",
		"=", "\\=",
		"|", "\\|",
		"{", "\\{",
		"}", "\\}",
		".", "\\.",
		"!", "\\!",
	)
	return replacer.Replace(text)
}

// getClientIP extracts the client IP address from the request
func getClientIP(r *http.Request) string {
	// Check X-Forwarded-For header first (for reverse proxies)
	if xff := r.Header.Get("X-Forwarded-For"); xff != "" {
		// X-Forwarded-For can contain multiple IPs, take the first one
		if idx := strings.Index(xff, ","); idx != -1 {
			return strings.TrimSpace(xff[:idx])
		}
		return strings.TrimSpace(xff)
	}

	// Check X-Real-IP header
	if xri := r.Header.Get("X-Real-IP"); xri != "" {
		return strings.TrimSpace(xri)
	}

	// Fall back to RemoteAddr
	if idx := strings.LastIndex(r.RemoteAddr, ":"); idx != -1 {
		return r.RemoteAddr[:idx]
	}
	return r.RemoteAddr
}

// healthHandler provides a simple health check endpoint
func (s *Server) healthHandler(w http.ResponseWriter, r *http.Request) {
	w.Header().Set("Content-Type", "application/json")
	w.WriteHeader(http.StatusOK)
	w.Write([]byte(`{"status":"healthy","service":"linuxservice"}`))
}

// aboutHandler handles the About Me page
func (s *Server) aboutHandler(w http.ResponseWriter, r *http.Request) {
	data := s.createPageData("Over mij - "+s.config.CompanyName, "about")
	// Populate dynamic About fields
	data.AboutName = "Brendon Bosman"
	now := time.Now()
	birthYear, birthMonth, birthDay := 1990, time.October, 17
	age := now.Year() - birthYear
	if now.Month() < birthMonth || (now.Month() == birthMonth && now.Day() < birthDay) {
		age--
	}
	data.AgeYears = age

	sonYear, sonMonth, sonDay := 2022, time.March, 11
	sonAge := now.Year() - sonYear
	if now.Month() < sonMonth || (now.Month() == sonMonth && now.Day() < sonDay) {
		sonAge--
	}
	data.SonAgeYears = sonAge

	s.renderTemplate(w, "over-mij.html", data)
}

// setupRoutes configures all HTTP routes
func (s *Server) setupRoutes() {
	// Static files
	fs := http.FileServer(http.Dir("static/"))
	http.Handle("/static/", http.StripPrefix("/static/", fs))

	// Page routes
	http.HandleFunc("/", s.homeHandler)
	http.HandleFunc("/contact", s.contactHandler)
	http.HandleFunc("/over-mij", s.aboutHandler)
	http.HandleFunc("/health", s.healthHandler)
}

func main() {
	server := NewServer()
	server.setupRoutes()

	log.Printf("Server starting on %s", server.config.Port)
	log.Fatal(http.ListenAndServe(server.config.Port, nil))
}
