package models

import (
	"fmt"
	"time"

	"odoo-go/pkg/orm"
)

// initPurchaseReport registers purchase.report — a transient model for purchase analysis.
// Mirrors: odoo/addons/purchase/report/purchase_report.py
//
//	class PurchaseReport(models.Model):
//	    _name = 'purchase.report'
//	    _description = 'Purchase Report'
//	    _auto = False
func initPurchaseReport() {
	m := orm.NewModel("purchase.report", orm.ModelOpts{
		Description: "Purchase Analysis Report",
		Type:        orm.ModelTransient,
	})

	m.AddFields(
		orm.Date("date_from", orm.FieldOpts{String: "Start Date"}),
		orm.Date("date_to", orm.FieldOpts{String: "End Date"}),
		orm.Many2one("partner_id", "res.partner", orm.FieldOpts{String: "Vendor"}),
		orm.Many2one("product_id", "product.product", orm.FieldOpts{String: "Product"}),
		orm.Many2one("product_tmpl_id", "product.template", orm.FieldOpts{String: "Product Template"}),
		orm.Many2one("company_id", "res.company", orm.FieldOpts{String: "Company"}),
		orm.Many2one("user_id", "res.users", orm.FieldOpts{String: "Representative"}),
		orm.Many2one("categ_id", "product.category", orm.FieldOpts{String: "Product Category"}),
		orm.Selection("state", []orm.SelectionItem{
			{Value: "draft", Label: "RFQ"},
			{Value: "purchase", Label: "Purchase Order"},
			{Value: "done", Label: "Done"},
			{Value: "cancel", Label: "Cancelled"},
		}, orm.FieldOpts{String: "Status"}),
	)

	// get_purchase_data: Aggregated purchase data for dashboards and reports.
	// Mirrors: odoo/addons/purchase/report/purchase_report.py (SQL view query)
	// Returns: { months, top_vendors, top_products, summary }
	m.RegisterMethod("get_purchase_data", func(rs *orm.Recordset, args ...interface{}) (interface{}, error) {
		env := rs.Env()

		// ── Spending by month (last 12 months) ──
		monthRows, err := env.Tx().Query(env.Ctx(), `
			SELECT date_trunc('month', po.date_order) AS month,
				COUNT(DISTINCT po.id) AS order_count,
				COALESCE(SUM(po.amount_total::float8), 0) AS spending,
				COALESCE(AVG(po.amount_total::float8), 0) AS avg_order
			FROM purchase_order po
			WHERE po.state IN ('purchase', 'done')
			GROUP BY month
			ORDER BY month DESC
			LIMIT 12`)
		if err != nil {
			return nil, fmt.Errorf("purchase_report: monthly spending query: %w", err)
		}
		defer monthRows.Close()

		var months []map[string]interface{}
		for monthRows.Next() {
			var month time.Time
			var cnt int64
			var spending, avg float64
			if err := monthRows.Scan(&month, &cnt, &spending, &avg); err != nil {
				continue
			}
			months = append(months, map[string]interface{}{
				"month":    month.Format("2006-01"),
				"orders":   cnt,
				"spending": spending,
				"avg_order": avg,
			})
		}

		// ── Top 10 vendors by spending ──
		vendorRows, err := env.Tx().Query(env.Ctx(), `
			SELECT p.name,
				COUNT(DISTINCT po.id) AS orders,
				COALESCE(SUM(po.amount_total::float8), 0) AS spending,
				COALESCE(AVG(po.amount_total::float8), 0) AS avg_order
			FROM purchase_order po
			JOIN res_partner p ON p.id = po.partner_id
			WHERE po.state IN ('purchase', 'done')
			GROUP BY p.id, p.name
			ORDER BY spending DESC
			LIMIT 10`)
		if err != nil {
			return nil, fmt.Errorf("purchase_report: top vendors query: %w", err)
		}
		defer vendorRows.Close()

		var vendors []map[string]interface{}
		for vendorRows.Next() {
			var name string
			var cnt int64
			var spending, avg float64
			if err := vendorRows.Scan(&name, &cnt, &spending, &avg); err != nil {
				continue
			}
			vendors = append(vendors, map[string]interface{}{
				"vendor":    name,
				"orders":    cnt,
				"spending":  spending,
				"avg_order": avg,
			})
		}

		// ── Top 10 products by purchase volume ──
		prodRows, err := env.Tx().Query(env.Ctx(), `
			SELECT pt.name,
				SUM(pol.product_qty) AS qty,
				COALESCE(SUM(pol.price_subtotal::float8), 0) AS spending,
				COUNT(DISTINCT pol.order_id) AS order_count
			FROM purchase_order_line pol
			JOIN purchase_order po ON po.id = pol.order_id AND po.state IN ('purchase', 'done')
			JOIN product_product pp ON pp.id = pol.product_id
			JOIN product_template pt ON pt.id = pp.product_tmpl_id
			WHERE pol.product_id IS NOT NULL
			GROUP BY pt.name
			ORDER BY spending DESC
			LIMIT 10`)
		if err != nil {
			return nil, fmt.Errorf("purchase_report: top products query: %w", err)
		}
		defer prodRows.Close()

		var products []map[string]interface{}
		for prodRows.Next() {
			var name string
			var qty, spending float64
			var orderCnt int64
			if err := prodRows.Scan(&name, &qty, &spending, &orderCnt); err != nil {
				continue
			}
			products = append(products, map[string]interface{}{
				"product":  name,
				"qty":      qty,
				"spending": spending,
				"orders":   orderCnt,
			})
		}

		// ── Summary totals ──
		var totalOrders int64
		var totalSpending, avgOrderValue float64
		env.Tx().QueryRow(env.Ctx(), `
			SELECT COUNT(*), COALESCE(SUM(amount_total::float8), 0), COALESCE(AVG(amount_total::float8), 0)
			FROM purchase_order WHERE state IN ('purchase', 'done')
		`).Scan(&totalOrders, &totalSpending, &avgOrderValue)

		return map[string]interface{}{
			"months":       months,
			"top_vendors":  vendors,
			"top_products": products,
			"summary": map[string]interface{}{
				"total_orders":    totalOrders,
				"total_spending":  totalSpending,
				"avg_order_value": avgOrderValue,
			},
		}, nil
	})

	// get_purchases_by_category: Breakdown by product category.
	// Mirrors: odoo/addons/purchase/report/purchase_report.py (grouped by categ_id)
	m.RegisterMethod("get_purchases_by_category", func(rs *orm.Recordset, args ...interface{}) (interface{}, error) {
		env := rs.Env()

		rows, err := env.Tx().Query(env.Ctx(), `
			SELECT COALESCE(pc.name, 'Uncategorized') AS category,
				COUNT(DISTINCT pol.order_id) AS orders,
				SUM(pol.product_qty) AS qty,
				COALESCE(SUM(pol.price_subtotal::float8), 0) AS spending
			FROM purchase_order_line pol
			JOIN purchase_order po ON po.id = pol.order_id AND po.state IN ('purchase', 'done')
			LEFT JOIN product_product pp ON pp.id = pol.product_id
			LEFT JOIN product_template pt ON pt.id = pp.product_tmpl_id
			LEFT JOIN product_category pc ON pc.id = pt.categ_id
			WHERE pol.product_id IS NOT NULL
			GROUP BY pc.name
			ORDER BY spending DESC`)
		if err != nil {
			return nil, fmt.Errorf("purchase_report: category query: %w", err)
		}
		defer rows.Close()

		var results []map[string]interface{}
		for rows.Next() {
			var name string
			var orders int64
			var qty, spending float64
			if err := rows.Scan(&name, &orders, &qty, &spending); err != nil {
				continue
			}
			results = append(results, map[string]interface{}{
				"category": name,
				"orders":   orders,
				"qty":      qty,
				"spending": spending,
			})
		}
		return results, nil
	})

	// get_bill_status_analysis: Invoice/bill status analysis.
	// Mirrors: odoo/addons/purchase/report/purchase_report.py (invoice_status grouping)
	m.RegisterMethod("get_bill_status_analysis", func(rs *orm.Recordset, args ...interface{}) (interface{}, error) {
		env := rs.Env()

		rows, err := env.Tx().Query(env.Ctx(), `
			SELECT COALESCE(invoice_status, 'no') AS status,
				COUNT(*) AS count,
				COALESCE(SUM(amount_total::float8), 0) AS spending
			FROM purchase_order
			WHERE state IN ('purchase', 'done')
			GROUP BY invoice_status
			ORDER BY spending DESC`)
		if err != nil {
			return nil, fmt.Errorf("purchase_report: bill status query: %w", err)
		}
		defer rows.Close()

		var results []map[string]interface{}
		for rows.Next() {
			var status string
			var count int64
			var spending float64
			if err := rows.Scan(&status, &count, &spending); err != nil {
				continue
			}
			results = append(results, map[string]interface{}{
				"status":   status,
				"count":    count,
				"spending": spending,
			})
		}
		return results, nil
	})

	// get_receipt_analysis: Receipt/delivery status analysis.
	// Mirrors: odoo/addons/purchase/report/purchase_report.py (receipt_status grouping)
	m.RegisterMethod("get_receipt_analysis", func(rs *orm.Recordset, args ...interface{}) (interface{}, error) {
		env := rs.Env()

		rows, err := env.Tx().Query(env.Ctx(), `
			SELECT
				CASE
					WHEN COALESCE(SUM(pol.qty_received), 0) = 0 THEN 'pending'
					WHEN SUM(pol.qty_received) < SUM(pol.product_qty) THEN 'partial'
					ELSE 'full'
				END AS status,
				COUNT(DISTINCT po.id) AS count,
				COALESCE(SUM(po.amount_total::float8), 0) AS spending
			FROM purchase_order po
			LEFT JOIN purchase_order_line pol ON pol.order_id = po.id
			WHERE po.state IN ('purchase', 'done')
			GROUP BY po.id`)
		if err != nil {
			return nil, fmt.Errorf("purchase_report: receipt analysis query: %w", err)
		}
		defer rows.Close()

		// Aggregate the per-PO results
		statusMap := map[string]map[string]interface{}{
			"pending": {"status": "pending", "count": int64(0), "spending": float64(0)},
			"partial": {"status": "partial", "count": int64(0), "spending": float64(0)},
			"full":    {"status": "full", "count": int64(0), "spending": float64(0)},
		}
		for rows.Next() {
			var status string
			var count int64
			var spending float64
			if err := rows.Scan(&status, &count, &spending); err != nil {
				continue
			}
			if entry, ok := statusMap[status]; ok {
				entry["count"] = entry["count"].(int64) + count
				entry["spending"] = entry["spending"].(float64) + spending
			}
		}

		var results []map[string]interface{}
		for _, v := range statusMap {
			if v["count"].(int64) > 0 {
				results = append(results, v)
			}
		}
		return results, nil
	})
}
