package server

import (
	"fmt"
	"strings"

	"odoo-go/pkg/orm"
)

// handleGetViews implements the get_views method.
// Mirrors: odoo/addons/base/models/ir_ui_view.py get_views()
func handleGetViews(env *orm.Environment, model string, params CallKWParams) (interface{}, *RPCError) {
	// Parse views list: [[false, "list"], [false, "form"], [false, "search"]]
	var viewRequests [][]interface{}
	if len(params.Args) > 0 {
		if vr, ok := params.Args[0].([]interface{}); ok {
			viewRequests = make([][]interface{}, len(vr))
			for i, v := range vr {
				if pair, ok := v.([]interface{}); ok {
					viewRequests[i] = pair
				}
			}
		}
	}
	// Also check kwargs
	if viewRequests == nil {
		if vr, ok := params.KW["views"].([]interface{}); ok {
			viewRequests = make([][]interface{}, len(vr))
			for i, v := range vr {
				if pair, ok := v.([]interface{}); ok {
					viewRequests[i] = pair
				}
			}
		}
	}

	views := make(map[string]interface{})
	for _, vr := range viewRequests {
		if len(vr) < 2 {
			continue
		}
		viewType, _ := vr[1].(string)
		if viewType == "" {
			continue
		}

		// Try to load from ir_ui_view table
		arch := loadViewArch(env, model, viewType)
		if arch == "" {
			// Generate default view
			arch = generateDefaultView(model, viewType)
		}

		views[viewType] = map[string]interface{}{
			"arch":         arch,
			"type":         viewType,
			"model":        model,
			"view_id":      0,
			"field_parent":  false,
		}
	}

	// Always include search view (client expects it)
	if _, hasSearch := views["search"]; !hasSearch {
		arch := loadViewArch(env, model, "search")
		if arch == "" {
			arch = generateDefaultView(model, "search")
		}
		views["search"] = map[string]interface{}{
			"arch":         arch,
			"type":         "search",
			"model":        model,
			"view_id":      0,
			"field_parent":  false,
		}
	}

	// Build models dict with field metadata
	models := map[string]interface{}{
		model: map[string]interface{}{
			"fields": fieldsGetForModel(model),
		},
	}

	return map[string]interface{}{
		"views":  views,
		"models": models,
	}, nil
}

// loadViewArch tries to load a view from the ir_ui_view table.
func loadViewArch(env *orm.Environment, model, viewType string) string {
	var arch string
	err := env.Tx().QueryRow(env.Ctx(),
		`SELECT arch FROM ir_ui_view WHERE model = $1 AND type = $2 AND active = true ORDER BY priority LIMIT 1`,
		model, viewType,
	).Scan(&arch)
	if err != nil {
		return ""
	}
	return arch
}

// generateDefaultView creates a minimal view XML for a model.
func generateDefaultView(modelName, viewType string) string {
	m := orm.Registry.Get(modelName)
	if m == nil {
		return fmt.Sprintf("<%s><field name=\"id\"/></%s>", viewType, viewType)
	}

	switch viewType {
	case "list", "tree":
		return generateDefaultListView(m)
	case "form":
		return generateDefaultFormView(m)
	case "search":
		return generateDefaultSearchView(m)
	case "kanban":
		return generateDefaultKanbanView(m)
	default:
		return fmt.Sprintf("<%s><field name=\"id\"/></%s>", viewType, viewType)
	}
}

func generateDefaultListView(m *orm.Model) string {
	// Prioritize important fields first
	priority := []string{"name", "display_name", "state", "partner_id", "date_order", "date",
		"amount_total", "amount_untaxed", "email", "phone", "company_id", "user_id",
		"product_id", "quantity", "price_unit", "price_subtotal"}

	var fields []string
	added := make(map[string]bool)

	// Add priority fields first
	for _, pf := range priority {
		f := m.GetField(pf)
		if f != nil && f.IsStored() && f.Type != orm.TypeBinary {
			fields = append(fields, fmt.Sprintf(`<field name="%s"/>`, pf))
			added[pf] = true
		}
	}

	// Fill remaining slots
	for _, f := range m.Fields() {
		if len(fields) >= 10 {
			break
		}
		if added[f.Name] || f.Name == "id" || !f.IsStored() ||
			f.Name == "create_uid" || f.Name == "write_uid" ||
			f.Name == "create_date" || f.Name == "write_date" ||
			f.Name == "password" || f.Name == "password_crypt" ||
			f.Type == orm.TypeBinary || f.Type == orm.TypeText || f.Type == orm.TypeHTML {
			continue
		}
		fields = append(fields, fmt.Sprintf(`<field name="%s"/>`, f.Name))
		added[f.Name] = true
	}

	return fmt.Sprintf("<list>\n  %s\n</list>", strings.Join(fields, "\n  "))
}

func generateDefaultFormView(m *orm.Model) string {
	skip := map[string]bool{
		"id": true, "create_uid": true, "write_uid": true,
		"create_date": true, "write_date": true,
		"password": true, "password_crypt": true,
	}

	// Header with action buttons and state widget
	// Mirrors: odoo form views with <header><button .../><field name="state" widget="statusbar"/></header>
	var header string
	if f := m.GetField("state"); f != nil && f.Type == orm.TypeSelection {
		var buttons []string
		// Generate buttons from registered methods that look like actions
		if m.Methods != nil {
			actionMethods := []struct{ method, label, stateFilter string }{
				{"action_confirm", "Confirm", "draft"},
				{"action_post", "Post", "draft"},
				{"action_done", "Done", "confirmed"},
				{"action_cancel", "Cancel", ""},
				{"button_cancel", "Cancel", ""},
				{"button_draft", "Reset to Draft", "cancel"},
				{"action_send", "Send", "posted"},
				{"create_invoices", "Create Invoice", "sale"},
			}
			for _, am := range actionMethods {
				if _, ok := m.Methods[am.method]; ok {
					attrs := ""
					if am.stateFilter != "" {
						attrs = fmt.Sprintf(` invisible="state != '%s'"`, am.stateFilter)
					}
					btnClass := "btn-secondary"
					if am.method == "action_confirm" || am.method == "action_post" {
						btnClass = "btn-primary"
					}
					buttons = append(buttons, fmt.Sprintf(
						`    <button name="%s" string="%s" type="object" class="%s"%s/>`,
						am.method, am.label, btnClass, attrs))
				}
			}
		}
		header = "  <header>\n"
		for _, btn := range buttons {
			header += btn + "\n"
		}
		header += `    <field name="state" widget="statusbar" clickable="1"/>
  </header>
`
	}

	// Title field (name or display_name)
	var title string
	if f := m.GetField("name"); f != nil {
		title = `    <div class="oe_title">
      <h1><field name="name" placeholder="Name..."/></h1>
    </div>
`
		skip["name"] = true
	}

	// Split fields into left/right groups
	var leftFields, rightFields []string
	var o2mFields []string
	count := 0

	// Prioritize important fields
	priority := []string{"partner_id", "date_order", "date", "company_id", "currency_id",
		"user_id", "journal_id", "product_id", "email", "phone"}

	for _, pf := range priority {
		f := m.GetField(pf)
		if f == nil || skip[pf] || f.Type == orm.TypeBinary {
			continue
		}
		skip[pf] = true
		line := fmt.Sprintf(`        <field name="%s"/>`, pf)
		if count%2 == 0 {
			leftFields = append(leftFields, line)
		} else {
			rightFields = append(rightFields, line)
		}
		count++
	}

	// Add remaining stored fields
	for _, f := range m.Fields() {
		if skip[f.Name] || !f.IsStored() || f.Type == orm.TypeBinary {
			continue
		}
		if f.Type == orm.TypeOne2many {
			o2mFields = append(o2mFields, fmt.Sprintf(`    <field name="%s"/>`, f.Name))
			continue
		}
		if f.Type == orm.TypeMany2many {
			continue
		}
		line := fmt.Sprintf(`        <field name="%s"/>`, f.Name)
		if len(leftFields) <= len(rightFields) {
			leftFields = append(leftFields, line)
		} else {
			rightFields = append(rightFields, line)
		}
		if len(leftFields)+len(rightFields) >= 20 {
			break
		}
	}

	// Build form
	var buf strings.Builder
	buf.WriteString("<form>\n")
	buf.WriteString(header)
	buf.WriteString("  <sheet>\n")
	buf.WriteString(title)
	buf.WriteString("    <group>\n")
	buf.WriteString("      <group>\n")
	buf.WriteString(strings.Join(leftFields, "\n"))
	buf.WriteString("\n      </group>\n")
	buf.WriteString("      <group>\n")
	buf.WriteString(strings.Join(rightFields, "\n"))
	buf.WriteString("\n      </group>\n")
	buf.WriteString("    </group>\n")

	// O2M fields in notebook
	if len(o2mFields) > 0 {
		buf.WriteString("    <notebook>\n")
		buf.WriteString("      <page string=\"Lines\">\n")
		buf.WriteString(strings.Join(o2mFields, "\n"))
		buf.WriteString("\n      </page>\n")
		buf.WriteString("    </notebook>\n")
	}

	buf.WriteString("  </sheet>\n")
	buf.WriteString("</form>")
	return buf.String()
}

func generateDefaultSearchView(m *orm.Model) string {
	var fields []string
	var filters []string

	// Search fields
	searchable := []string{"name", "display_name", "email", "phone", "ref",
		"partner_id", "company_id", "user_id", "state", "date_order", "date"}
	for _, sf := range searchable {
		if f := m.GetField(sf); f != nil {
			fields = append(fields, fmt.Sprintf(`<field name="%s"/>`, sf))
		}
	}
	if len(fields) == 0 {
		fields = append(fields, `<field name="id"/>`)
	}

	// Auto-generate filter for state field
	if f := m.GetField("state"); f != nil && f.Type == orm.TypeSelection {
		for _, sel := range f.Selection {
			filters = append(filters, fmt.Sprintf(
				`<filter string="%s" name="filter_%s" domain="[('state','=','%s')]"/>`,
				sel.Label, sel.Value, sel.Value))
		}
	}

	// Group-by for common fields
	var groupby []string
	groupable := []string{"partner_id", "state", "company_id", "user_id", "stage_id"}
	for _, gf := range groupable {
		if f := m.GetField(gf); f != nil {
			groupby = append(groupby, fmt.Sprintf(`<filter string="%s" name="groupby_%s" context="{'group_by': '%s'}"/>`,
				f.String, gf, gf))
		}
	}

	var buf strings.Builder
	buf.WriteString("<search>\n")
	for _, f := range fields {
		buf.WriteString("  " + f + "\n")
	}
	if len(filters) > 0 {
		buf.WriteString("  <separator/>\n")
		for _, f := range filters {
			buf.WriteString("  " + f + "\n")
		}
	}
	if len(groupby) > 0 {
		buf.WriteString("  <group expand=\"0\" string=\"Group By\">\n")
		for _, g := range groupby {
			buf.WriteString("    " + g + "\n")
		}
		buf.WriteString("  </group>\n")
	}
	buf.WriteString("</search>")
	return buf.String()
}

func generateDefaultKanbanView(m *orm.Model) string {
	nameField := "name"
	if f := m.GetField("name"); f == nil {
		nameField = "id"
	}

	// Build a richer card with available fields
	var cardFields []string

	// Title
	cardFields = append(cardFields, fmt.Sprintf(`      <field name="%s" class="fw-bold fs-5"/>`, nameField))

	// Partner/customer
	if f := m.GetField("partner_id"); f != nil {
		cardFields = append(cardFields, `      <field name="partner_id"/>`)
	}

	// Revenue/amount
	for _, amtField := range []string{"expected_revenue", "amount_total", "amount_untaxed"} {
		if f := m.GetField(amtField); f != nil {
			cardFields = append(cardFields, fmt.Sprintf(`      <field name="%s"/>`, amtField))
			break
		}
	}

	// Date
	for _, dateField := range []string{"date_order", "date", "date_deadline"} {
		if f := m.GetField(dateField); f != nil {
			cardFields = append(cardFields, fmt.Sprintf(`      <field name="%s"/>`, dateField))
			break
		}
	}

	// User/assignee
	if f := m.GetField("user_id"); f != nil {
		cardFields = append(cardFields, `      <field name="user_id" widget="many2one_avatar_user"/>`)
	}

	return fmt.Sprintf(`<kanban>
  <templates>
    <t t-name="card">
%s
    </t>
  </templates>
</kanban>`, strings.Join(cardFields, "\n"))
}
