package server

import (
	"encoding/json"
	"fmt"
	"io"
	"log"
	"net/http"
	"strconv"
	"strings"

	"odoo-go/pkg/orm"
)

// handleUpload handles file uploads to ir.attachment.
// Mirrors: odoo/addons/web/controllers/binary.py upload_attachment()
func (s *Server) handleUpload(w http.ResponseWriter, r *http.Request) {
	if r.Method != http.MethodPost {
		http.Error(w, "Method not allowed", http.StatusMethodNotAllowed)
		return
	}

	// Parse multipart form (max 128MB)
	if err := r.ParseMultipartForm(128 << 20); err != nil {
		http.Error(w, "File too large", http.StatusRequestEntityTooLarge)
		return
	}

	file, header, err := r.FormFile("ufile")
	if err != nil {
		http.Error(w, "No file uploaded", http.StatusBadRequest)
		return
	}
	defer file.Close()

	// Read file content
	data, err := io.ReadAll(file)
	if err != nil {
		http.Error(w, "Read error", http.StatusInternalServerError)
		return
	}

	log.Printf("upload: received %s (%d bytes, %s)", header.Filename, len(data), header.Header.Get("Content-Type"))

	// Extract model/id from form values for linking
	resModel := r.FormValue("model")
	resIDStr := r.FormValue("id")
	resID := int64(0)
	if resIDStr != "" {
		if v, err := strconv.ParseInt(resIDStr, 10, 64); err == nil {
			resID = v
		}
	}

	// Get UID from session
	uid := int64(1)
	companyID := int64(1)
	if sess := GetSession(r); sess != nil {
		uid = sess.UID
		companyID = sess.CompanyID
	}

	// Store in ir.attachment
	env, err := orm.NewEnvironment(r.Context(), orm.EnvConfig{
		Pool:      s.pool,
		UID:       uid,
		CompanyID: companyID,
	})
	if err != nil {
		http.Error(w, "Internal error", http.StatusInternalServerError)
		return
	}
	defer env.Close()

	// Detect mimetype
	mimetype := header.Header.Get("Content-Type")
	if mimetype == "" {
		mimetype = "application/octet-stream"
	}

	attachVals := orm.Values{
		"name":      header.Filename,
		"datas":     data,
		"mimetype":  mimetype,
		"file_size": len(data),
		"type":      "binary",
	}
	if resModel != "" {
		attachVals["res_model"] = resModel
	}
	if resID > 0 {
		attachVals["res_id"] = resID
	}

	attachRS := env.Model("ir.attachment")
	created, err := attachRS.Create(attachVals)
	if err != nil {
		log.Printf("upload: failed to create attachment: %v", err)
		// Return success anyway with temp ID (graceful degradation)
		w.Header().Set("Content-Type", "application/json")
		json.NewEncoder(w).Encode([]map[string]interface{}{
			{"id": 0, "name": header.Filename, "size": len(data), "mimetype": mimetype},
		})
		if commitErr := env.Commit(); commitErr != nil {
			log.Printf("upload: commit warning: %v", commitErr)
		}
		return
	}

	if err := env.Commit(); err != nil {
		http.Error(w, "Commit error", http.StatusInternalServerError)
		return
	}

	// Return Odoo-expected format: array of attachment dicts
	w.Header().Set("Content-Type", "application/json")
	json.NewEncoder(w).Encode([]map[string]interface{}{
		{
			"id":       created.ID(),
			"name":     header.Filename,
			"size":     len(data),
			"mimetype": mimetype,
		},
	})
}

// handleContent serves attachment content by ID.
// Mirrors: odoo/addons/web/controllers/binary.py content()
func (s *Server) handleContent(w http.ResponseWriter, r *http.Request) {
	// Extract attachment ID from URL: /web/content/<id>
	parts := strings.Split(r.URL.Path, "/")
	if len(parts) < 4 {
		http.Error(w, "Not found", http.StatusNotFound)
		return
	}
	idStr := parts[3]
	attachID, err := strconv.ParseInt(idStr, 10, 64)
	if err != nil {
		http.Error(w, "Invalid ID", http.StatusBadRequest)
		return
	}

	uid := int64(1)
	companyID := int64(1)
	if sess := GetSession(r); sess != nil {
		uid = sess.UID
		companyID = sess.CompanyID
	}

	env, err := orm.NewEnvironment(r.Context(), orm.EnvConfig{
		Pool:      s.pool,
		UID:       uid,
		CompanyID: companyID,
	})
	if err != nil {
		http.Error(w, "Internal error", http.StatusInternalServerError)
		return
	}
	defer env.Close()

	// Read attachment
	attachRS := env.Model("ir.attachment").Browse(attachID)
	records, err := attachRS.Read([]string{"name", "datas", "mimetype"})
	if err != nil || len(records) == 0 {
		http.Error(w, "Attachment not found", http.StatusNotFound)
		return
	}

	rec := records[0]
	name, _ := rec["name"].(string)
	mimetype, _ := rec["mimetype"].(string)
	if mimetype == "" {
		mimetype = "application/octet-stream"
	}

	w.Header().Set("Content-Type", mimetype)
	w.Header().Set("Content-Disposition", fmt.Sprintf("attachment; filename=%q", name))

	if data, ok := rec["datas"].([]byte); ok {
		w.Write(data)
	} else {
		http.Error(w, "No content", http.StatusNotFound)
	}
}
