package freecad

import (
	"bytes"
	"encoding/json"
	"fmt"
	"io"
	"mime/multipart"
	"net/http"
	"os"
	"path/filepath"
	"time"

	FikoYTCtx "server/sistem/fikoyt_ctx"

	"github.com/gofiber/fiber/v3"
	"github.com/gofiber/fiber/v3/middleware/cors"
)

// FreeCAD Python API URL
var freecadAPIURL = os.Getenv("FREECAD_API_URL")

func init() {
	if freecadAPIURL == "" {
		freecadAPIURL = "http://localhost:8090" // Varsayılan
	}
}

// FreeCAD API Response yapıları
type FreecadAnalysisResponse struct {
	Success   bool                   `json:"success"`
	Data      map[string]interface{} `json:"data,omitempty"`
	Message   string                 `json:"message"`
	Error     string                 `json:"error,omitempty"`
	Traceback string                 `json:"traceback,omitempty"`
}

type MaterialListResponse struct {
	Success   bool                     `json:"success"`
	Materials []map[string]interface{} `json:"materials,omitempty"`
}

// Init - FreeCAD API router'ı başlat
func Init(app *fiber.App, api fiber.Router) {
	freecad := api.Group("/freecad")

	// STEP dosya analizi
	freecad.Post("/analyze", analyzeStepFile)

	// Malzeme listesi
	freecad.Get("/materials", listMaterials)

	// Health check
	freecad.Get("/health", healthCheck)

	// STEP dosya render (GIF) - RAW endpoint, CORS enabled
	rawGroup := app.Group("/uyar/api-raw/freecad")
	rawGroup.Use(cors.New(cors.Config{
		AllowOrigins:     []string{"*"},
		AllowMethods:     []string{"POST", "OPTIONS"},
		AllowHeaders:     []string{"*"},
		AllowCredentials: false,
	}))
	rawGroup.Post("/render", renderStepFileRaw)
}

// analyzeStepFile - STEP dosyasını FreeCAD ile analiz et
func analyzeStepFile(c fiber.Ctx) error {
	FikoYT := c.Locals("FikoYTCtx").(*FikoYTCtx.FikoYTCtx)

	// Response başlat
	FikoYT.Cevap.AyarlaDurumKodu(200)
	FikoYT.Cevap.Durum.Tamamlandi = false
	FikoYT.Cevap.Durum.Hata = false

	// Dosya kontrolü
	file, err := c.FormFile("file")
	if err != nil {
		FikoYT.Cevap.AyarlaDurumKodu(400)
		FikoYT.Cevap.Durum.Hata = true
		FikoYT.Cevap.Durum.Mesaj = "STEP dosyası bulunamadı"
		FikoYT.Cevap.Sonuc = map[string]interface{}{
			"error": "No file uploaded",
		}
		return c.JSON(FikoYT.Cevap)
	}

	// Dosya uzantısı kontrolü
	ext := filepath.Ext(file.Filename)
	if ext != ".stp" && ext != ".step" && ext != ".STP" && ext != ".STEP" {
		FikoYT.Cevap.AyarlaDurumKodu(400)
		FikoYT.Cevap.Durum.Hata = true
		FikoYT.Cevap.Durum.Mesaj = "Sadece .stp veya .step dosyaları kabul edilir"
		FikoYT.Cevap.Sonuc = map[string]interface{}{
			"error": "Invalid file type",
		}
		return c.JSON(FikoYT.Cevap)
	}

	// Parametreleri al
	material := c.FormValue("material", "aluminium")
	density := c.FormValue("density", "")
	precision := c.FormValue("precision", "")

	// Dosyayı aç
	fileReader, err := file.Open()
	if err != nil {
		FikoYT.Cevap.AyarlaDurumKodu(500)
		FikoYT.Cevap.Durum.Hata = true
		FikoYT.Cevap.Durum.Mesaj = "Dosya açılamadı"
		FikoYT.Cevap.Sonuc = map[string]interface{}{
			"error": err.Error(),
		}
		return c.JSON(FikoYT.Cevap)
	}
	defer fileReader.Close()

	// Multipart form oluştur
	var requestBody bytes.Buffer
	writer := multipart.NewWriter(&requestBody)

	// Dosya ekle
	part, err := writer.CreateFormFile("file", file.Filename)
	if err != nil {
		FikoYT.Cevap.AyarlaDurumKodu(500)
		FikoYT.Cevap.Durum.Hata = true
		FikoYT.Cevap.Durum.Mesaj = "Multipart form oluşturulamadı"
		FikoYT.Cevap.Sonuc = map[string]interface{}{
			"error": err.Error(),
		}
		return c.JSON(FikoYT.Cevap)
	}

	_, err = io.Copy(part, fileReader)
	if err != nil {
		FikoYT.Cevap.AyarlaDurumKodu(500)
		FikoYT.Cevap.Durum.Hata = true
		FikoYT.Cevap.Durum.Mesaj = "Dosya kopyalanamadı"
		FikoYT.Cevap.Sonuc = map[string]interface{}{
			"error": err.Error(),
		}
		return c.JSON(FikoYT.Cevap)
	}

	// Parametreleri ekle
	if material != "" {
		writer.WriteField("material", material)
	}
	if density != "" {
		writer.WriteField("density", density)
	}
	if precision != "" {
		writer.WriteField("precision", precision)
	}

	writer.Close()

	// Python API'ye istek gönder
	apiURL := fmt.Sprintf("%s/analyze", freecadAPIURL)
	req, err := http.NewRequest("POST", apiURL, &requestBody)
	if err != nil {
		FikoYT.Cevap.AyarlaDurumKodu(500)
		FikoYT.Cevap.Durum.Hata = true
		FikoYT.Cevap.Durum.Mesaj = "API isteği oluşturulamadı"
		FikoYT.Cevap.Sonuc = map[string]interface{}{
			"error": err.Error(),
		}
		return c.JSON(FikoYT.Cevap)
	}

	req.Header.Set("Content-Type", writer.FormDataContentType())

	// HTTP client (timeout ile)
	client := &http.Client{
		Timeout: 120 * time.Second, // 2 dakika timeout
	}

	resp, err := client.Do(req)
	if err != nil {
		FikoYT.Cevap.AyarlaDurumKodu(500)
		FikoYT.Cevap.Durum.Hata = true
		FikoYT.Cevap.Durum.Mesaj = "FreeCAD API'ye bağlanılamadı"
		FikoYT.Cevap.Sonuc = map[string]interface{}{
			"error":   err.Error(),
			"api_url": apiURL,
		}
		return c.JSON(FikoYT.Cevap)
	}
	defer resp.Body.Close()

	// Response oku
	responseBody, err := io.ReadAll(resp.Body)
	if err != nil {
		FikoYT.Cevap.AyarlaDurumKodu(500)
		FikoYT.Cevap.Durum.Hata = true
		FikoYT.Cevap.Durum.Mesaj = "API response okunamadı"
		FikoYT.Cevap.Sonuc = map[string]interface{}{
			"error": err.Error(),
		}
		return c.JSON(FikoYT.Cevap)
	}

	// JSON parse
	var freecadResponse FreecadAnalysisResponse
	err = json.Unmarshal(responseBody, &freecadResponse)
	if err != nil {
		FikoYT.Cevap.AyarlaDurumKodu(500)
		FikoYT.Cevap.Durum.Hata = true
		FikoYT.Cevap.Durum.Mesaj = "API response parse edilemedi"
		FikoYT.Cevap.Sonuc = map[string]interface{}{
			"error":    err.Error(),
			"response": string(responseBody),
		}
		return c.JSON(FikoYT.Cevap)
	}

	// FreeCAD API başarılı mı?
	if !freecadResponse.Success {
		FikoYT.Cevap.AyarlaDurumKodu(500)
		FikoYT.Cevap.Durum.Hata = true
		FikoYT.Cevap.Durum.Mesaj = freecadResponse.Message
		FikoYT.Cevap.Sonuc = map[string]interface{}{
			"error":     freecadResponse.Error,
			"message":   freecadResponse.Message,
			"traceback": freecadResponse.Traceback,
		}
		return c.JSON(FikoYT.Cevap)
	}

	// Başarılı response
	FikoYT.Cevap.AyarlaDurumKodu(200)
	FikoYT.Cevap.Durum.Tamamlandi = true
	FikoYT.Cevap.Durum.Mesaj = "STEP dosyası başarıyla analiz edildi"
	FikoYT.Cevap.Sonuc = freecadResponse.Data

	return c.JSON(FikoYT.Cevap)
}

// listMaterials - Mevcut malzeme listesini döndür
func listMaterials(c fiber.Ctx) error {
	FikoYT := c.Locals("FikoYTCtx").(*FikoYTCtx.FikoYTCtx)

	// Response başlat
	FikoYT.Cevap.AyarlaDurumKodu(200)
	FikoYT.Cevap.Durum.Tamamlandi = false
	FikoYT.Cevap.Durum.Hata = false

	// Python API'ye istek gönder
	apiURL := fmt.Sprintf("%s/materials", freecadAPIURL)
	resp, err := http.Get(apiURL)
	if err != nil {
		FikoYT.Cevap.AyarlaDurumKodu(500)
		FikoYT.Cevap.Durum.Hata = true
		FikoYT.Cevap.Durum.Mesaj = "FreeCAD API'ye bağlanılamadı"
		FikoYT.Cevap.Sonuc = map[string]interface{}{
			"error": err.Error(),
		}
		return c.JSON(FikoYT.Cevap)
	}
	defer resp.Body.Close()

	// Response oku
	responseBody, err := io.ReadAll(resp.Body)
	if err != nil {
		FikoYT.Cevap.AyarlaDurumKodu(500)
		FikoYT.Cevap.Durum.Hata = true
		FikoYT.Cevap.Durum.Mesaj = "API response okunamadı"
		FikoYT.Cevap.Sonuc = map[string]interface{}{
			"error": err.Error(),
		}
		return c.JSON(FikoYT.Cevap)
	}

	// JSON parse
	var materialResponse MaterialListResponse
	err = json.Unmarshal(responseBody, &materialResponse)
	if err != nil {
		FikoYT.Cevap.AyarlaDurumKodu(500)
		FikoYT.Cevap.Durum.Hata = true
		FikoYT.Cevap.Durum.Mesaj = "API response parse edilemedi"
		FikoYT.Cevap.Sonuc = map[string]interface{}{
			"error": err.Error(),
		}
		return c.JSON(FikoYT.Cevap)
	}

	// Başarılı response
	FikoYT.Cevap.AyarlaDurumKodu(200)
	FikoYT.Cevap.Durum.Tamamlandi = true
	FikoYT.Cevap.Durum.Mesaj = "Malzeme listesi başarıyla alındı"
	FikoYT.Cevap.Sonuc = map[string]interface{}{
		"materials": materialResponse.Materials,
	}

	return c.JSON(FikoYT.Cevap)
}

// healthCheck - FreeCAD API'nin sağlık kontrolü
func healthCheck(c fiber.Ctx) error {
	FikoYT := c.Locals("FikoYTCtx").(*FikoYTCtx.FikoYTCtx)

	// Response başlat
	FikoYT.Cevap.AyarlaDurumKodu(200)
	FikoYT.Cevap.Durum.Tamamlandi = false
	FikoYT.Cevap.Durum.Hata = false

	// Python API'ye istek gönder
	apiURL := fmt.Sprintf("%s/health", freecadAPIURL)
	resp, err := http.Get(apiURL)
	if err != nil {
		FikoYT.Cevap.AyarlaDurumKodu(500)
		FikoYT.Cevap.Durum.Hata = true
		FikoYT.Cevap.Durum.Mesaj = "FreeCAD API çalışmıyor"
		FikoYT.Cevap.Sonuc = map[string]interface{}{
			"status":  "down",
			"error":   err.Error(),
			"api_url": apiURL,
		}
		return c.JSON(FikoYT.Cevap)
	}
	defer resp.Body.Close()

	// Response oku
	var healthResponse map[string]interface{}
	json.NewDecoder(resp.Body).Decode(&healthResponse)

	// Başarılı response
	FikoYT.Cevap.AyarlaDurumKodu(200)
	FikoYT.Cevap.Durum.Tamamlandi = true
	FikoYT.Cevap.Durum.Mesaj = "FreeCAD API çalışıyor"
	FikoYT.Cevap.Sonuc = healthResponse

	return c.JSON(FikoYT.Cevap)
}

// renderStepFileRaw - STEP dosyasından GIF render oluştur (RAW endpoint)
func renderStepFileRaw(c fiber.Ctx) error {
	fmt.Println("[RENDER] Request received")

	// Binary response - no middleware
	c.Set("Content-Type", "image/gif")

	// Dosya kontrolü
	file, err := c.FormFile("file")
	if err != nil {
		fmt.Printf("[RENDER ERROR] FormFile error: %v\n", err)
		return c.Status(400).JSON(fiber.Map{
			"success": false,
			"error":   "No file uploaded",
			"message": "STEP dosyası bulunamadı",
		})
	}

	fmt.Printf("[RENDER] File received: %s\n", file.Filename)

	// Dosya uzantısı kontrolü
	ext := filepath.Ext(file.Filename)
	if ext != ".stp" && ext != ".step" && ext != ".STP" && ext != ".STEP" {
		return c.Status(400).JSON(fiber.Map{
			"success": false,
			"error":   "Invalid file type",
			"message": "Sadece .stp veya .step dosyaları kabul edilir",
		})
	}

	// Dosyayı aç
	fileReader, err := file.Open()
	if err != nil {
		return c.Status(500).JSON(fiber.Map{
			"success": false,
			"error":   err.Error(),
			"message": "Dosya açılamadı",
		})
	}
	defer fileReader.Close()

	// Multipart form oluştur
	var requestBody bytes.Buffer
	writer := multipart.NewWriter(&requestBody)

	// Dosya ekle
	part, err := writer.CreateFormFile("file", file.Filename)
	if err != nil {
		return c.Status(500).JSON(fiber.Map{
			"success": false,
			"error":   err.Error(),
			"message": "Multipart form oluşturulamadı",
		})
	}

	_, err = io.Copy(part, fileReader)
	if err != nil {
		return c.Status(500).JSON(fiber.Map{
			"success": false,
			"error":   err.Error(),
			"message": "Dosya kopyalanamadı",
		})
	}

	writer.Close()

	// Python API'ye istek gönder
	apiURL := fmt.Sprintf("%s/render", freecadAPIURL)
	req, err := http.NewRequest("POST", apiURL, &requestBody)
	if err != nil {
		return c.Status(500).JSON(fiber.Map{
			"success": false,
			"error":   err.Error(),
			"message": "API isteği oluşturulamadı",
		})
	}

	req.Header.Set("Content-Type", writer.FormDataContentType())

	// HTTP client (uzun timeout)
	client := &http.Client{
		Timeout: 300 * time.Second, // 5 dakika timeout (render uzun sürebilir)
	}

	resp, err := client.Do(req)
	if err != nil {
		return c.Status(500).JSON(fiber.Map{
			"success": false,
			"error":   err.Error(),
			"message": "FreeCAD API'ye bağlanılamadı",
		})
	}
	defer resp.Body.Close()

	// Hata kontrolü
	if resp.StatusCode != 200 {
		fmt.Printf("[RENDER ERROR] Python API error: %d\n", resp.StatusCode)
		responseBody, _ := io.ReadAll(resp.Body)
		return c.Status(resp.StatusCode).JSON(fiber.Map{
			"success": false,
			"error":   string(responseBody),
			"message": "Render hatası",
		})
	}

	fmt.Println("[RENDER] Python API response 200, reading GIF...")

	// GIF'i memory'ye al
	gifData, err := io.ReadAll(resp.Body)
	if err != nil {
		fmt.Printf("[RENDER ERROR] ReadAll error: %v\n", err)
		return c.Status(500).JSON(fiber.Map{
			"success": false,
			"error":   err.Error(),
			"message": "GIF okunamadı",
		})
	}

	fmt.Printf("[RENDER] GIF read successfully (%d bytes)\n", len(gifData))

	// GIF'i döndür
	c.Set("Content-Type", "image/gif")
	c.Set("Content-Length", fmt.Sprintf("%d", len(gifData)))
	c.Set("Content-Disposition", fmt.Sprintf("attachment; filename=\"%s.gif\"",
		file.Filename[:len(file.Filename)-len(ext)]))

	fmt.Println("[RENDER] Sending GIF to client...")
	return c.Send(gifData)
}
