package models

import (
	"fmt"

	"odoo-go/pkg/orm"
)

// initCrmTeamExpanded extends the basic crm.team with CRM-specific fields
// (pipeline dashboard, lead assignment, team configuration).
// Mirrors: odoo/addons/crm/models/crm_team.py CrmTeam
func initCrmTeamExpanded() {
	m := orm.ExtendModel("crm.team")

	m.AddFields(
		// Team configuration
		orm.Many2one("user_id", "res.users", orm.FieldOpts{String: "Team Leader"}),
		orm.One2many("crm_team_member_ids", "crm.team.member", "crm_team_id", orm.FieldOpts{
			String: "Sales Team Members",
		}),
		orm.Boolean("use_leads", orm.FieldOpts{
			String:  "Leads",
			Default: true,
			Help:    "Check this box to filter and qualify leads.",
		}),
		orm.Boolean("use_opportunities", orm.FieldOpts{
			String:  "Pipeline",
			Default: true,
			Help:    "Check this box to manage a pipeline of opportunities.",
		}),
		orm.Many2one("alias_id", "mail.alias", orm.FieldOpts{
			String: "Email Alias",
			Help:   "Incoming emails on this alias will create leads/opportunities.",
		}),

		// Dashboard computed fields
		// Mirrors: _compute_opportunities_data in crm.team
		orm.Integer("opportunities_count", orm.FieldOpts{
			String:  "Number of Opportunities",
			Compute: "_compute_counts",
			Help:    "Number of active opportunities in this team's pipeline.",
		}),
		orm.Monetary("opportunities_amount", orm.FieldOpts{
			String:        "Opportunities Revenue",
			Compute:       "_compute_counts",
			CurrencyField: "currency_id",
			Help:          "Total expected revenue of active opportunities.",
		}),
		orm.Many2one("currency_id", "res.currency", orm.FieldOpts{
			String: "Currency",
		}),
		orm.Integer("unassigned_leads_count", orm.FieldOpts{
			String:  "Unassigned Leads",
			Compute: "_compute_counts",
			Help:    "Number of leads without a salesperson assigned.",
		}),

		// Assignment settings
		// Mirrors: odoo/addons/crm/models/crm_team.py assignment fields
		orm.Selection("assignment_domain", []orm.SelectionItem{
			{Value: "manual", Label: "Manual"},
			{Value: "auto", Label: "Auto Assignment"},
		}, orm.FieldOpts{
			String:  "Assignment Method",
			Default: "manual",
			Help:    "How new leads are distributed among team members.",
		}),
		orm.Integer("assignment_max", orm.FieldOpts{
			String:  "Max Leads per Cycle",
			Default: 30,
			Help:    "Maximum leads assigned to a member per assignment cycle.",
		}),
		orm.Boolean("assignment_enabled", orm.FieldOpts{
			String: "Auto-Assignment Active",
			Help:   "Enable automatic lead assignment for this team.",
		}),
		orm.Integer("assignment_optout_count", orm.FieldOpts{
			String:  "Members Opted-Out",
			Compute: "_compute_assignment_optout",
			Help:    "Number of members who opted out of automatic assignment.",
		}),
	)

	// _compute_counts: compute dashboard KPIs for the sales team.
	// Mirrors: odoo/addons/crm/models/crm_team.py _compute_opportunities_data
	m.RegisterCompute("opportunities_count", func(rs *orm.Recordset) (orm.Values, error) {
		env := rs.Env()
		teamID := rs.IDs()[0]

		var count int64
		var amount float64
		_ = env.Tx().QueryRow(env.Ctx(),
			`SELECT COUNT(*), COALESCE(SUM(expected_revenue::float8), 0)
			 FROM crm_lead
			 WHERE team_id = $1 AND active = true AND type = 'opportunity'`,
			teamID,
		).Scan(&count, &amount)

		var unassigned int64
		_ = env.Tx().QueryRow(env.Ctx(),
			`SELECT COUNT(*)
			 FROM crm_lead
			 WHERE team_id = $1 AND active = true AND user_id IS NULL`,
			teamID,
		).Scan(&unassigned)

		return orm.Values{
			"opportunities_count":    count,
			"opportunities_amount":   amount,
			"unassigned_leads_count": unassigned,
		}, nil
	})

	// action_assign_leads: trigger automatic lead assignment.
	// Mirrors: odoo/addons/crm/models/crm_team.py action_assign_leads
	m.RegisterMethod("action_assign_leads", func(rs *orm.Recordset, args ...interface{}) (interface{}, error) {
		env := rs.Env()
		teamID := rs.IDs()[0]

		// Fetch active members with remaining capacity
		rows, err := env.Tx().Query(env.Ctx(), `
			SELECT m.user_id, COALESCE(m.assignment_max, 30) AS max_leads,
			       COALESCE((SELECT COUNT(*) FROM crm_lead l
			                 WHERE l.user_id = m.user_id AND l.team_id = $1
			                   AND l.active = true
			                   AND l.create_date >= date_trunc('month', CURRENT_DATE)), 0) AS current_count
			FROM crm_team_member m
			WHERE m.crm_team_id = $1 AND m.active = true
			ORDER BY current_count ASC`,
			teamID)
		if err != nil {
			return nil, fmt.Errorf("action_assign_leads: query members: %w", err)
		}
		defer rows.Close()

		type memberCap struct {
			userID   int64
			capacity int64
		}
		var members []memberCap
		for rows.Next() {
			var uid int64
			var maxLeads, current int64
			if err := rows.Scan(&uid, &maxLeads, &current); err != nil {
				return nil, err
			}
			if remaining := maxLeads - current; remaining > 0 {
				members = append(members, memberCap{userID: uid, capacity: remaining})
			}
		}
		if len(members) == 0 {
			return map[string]interface{}{"assigned": 0}, nil
		}

		// Fetch unassigned leads
		leadRows, err := env.Tx().Query(env.Ctx(), `
			SELECT id FROM crm_lead
			WHERE team_id = $1 AND active = true AND user_id IS NULL
			ORDER BY priority DESC, id ASC`,
			teamID)
		if err != nil {
			return nil, fmt.Errorf("action_assign_leads: query leads: %w", err)
		}
		defer leadRows.Close()

		var assigned int64
		memberIdx := 0
		for leadRows.Next() {
			var leadID int64
			if err := leadRows.Scan(&leadID); err != nil {
				return nil, err
			}
			if memberIdx >= len(members) {
				break
			}
			mc := &members[memberIdx]
			_, _ = env.Tx().Exec(env.Ctx(),
				`UPDATE crm_lead SET user_id = $1 WHERE id = $2`, mc.userID, leadID)
			assigned++
			mc.capacity--
			if mc.capacity <= 0 {
				memberIdx++
			}
		}

		return map[string]interface{}{"assigned": assigned}, nil
	})

	// action_open_opportunities: return window action for team's opportunities.
	// Mirrors: odoo/addons/crm/models/crm_team.py action_open_opportunities
	m.RegisterMethod("action_open_opportunities", func(rs *orm.Recordset, args ...interface{}) (interface{}, error) {
		return map[string]interface{}{
			"type":      "ir.actions.act_window",
			"name":      "Opportunities",
			"res_model": "crm.lead",
			"view_mode": "kanban,tree,form",
			"domain":    fmt.Sprintf("[('team_id','=',%d),('type','=','opportunity')]", rs.IDs()[0]),
			"context":   map[string]interface{}{"default_team_id": rs.IDs()[0], "default_type": "opportunity"},
		}, nil
	})

	// action_open_unassigned: return window action for unassigned leads.
	// Mirrors: odoo/addons/crm/models/crm_team.py (dashboard actions)
	m.RegisterMethod("action_open_unassigned", func(rs *orm.Recordset, args ...interface{}) (interface{}, error) {
		return map[string]interface{}{
			"type":      "ir.actions.act_window",
			"name":      "Unassigned Leads",
			"res_model": "crm.lead",
			"view_mode": "tree,form",
			"domain":    fmt.Sprintf("[('team_id','=',%d),('user_id','=',False)]", rs.IDs()[0]),
			"context":   map[string]interface{}{"default_team_id": rs.IDs()[0]},
		}, nil
	})
}

// initCrmTeamMember registers the crm.team.member model.
// Mirrors: odoo/addons/crm/models/crm_team_member.py CrmTeamMember
func initCrmTeamMember() {
	m := orm.NewModel("crm.team.member", orm.ModelOpts{
		Description: "Sales Team Member",
	})

	m.AddFields(
		orm.Many2one("crm_team_id", "crm.team", orm.FieldOpts{
			String:   "Sales Team",
			Required: true,
			OnDelete: orm.OnDeleteCascade,
			Index:    true,
		}),
		orm.Many2one("user_id", "res.users", orm.FieldOpts{
			String:   "Salesperson",
			Required: true,
			Index:    true,
		}),
		orm.Boolean("active", orm.FieldOpts{String: "Active", Default: true}),
		orm.Float("assignment_max", orm.FieldOpts{
			String:  "Max Leads",
			Help:    "Maximum number of leads this member should be assigned per month.",
			Default: float64(30),
		}),
		orm.Integer("lead_month_count", orm.FieldOpts{
			String:  "Leads This Month",
			Compute: "_compute_lead_count",
			Help:    "Number of leads assigned to this member in the current month.",
		}),
		orm.Boolean("assignment_optout", orm.FieldOpts{
			String: "Opt-Out",
			Help:   "If checked, this member will not receive automatically assigned leads.",
		}),
		orm.Many2one("company_id", "res.company", orm.FieldOpts{
			String: "Company",
			Help:   "Company of the sales team.",
		}),
	)

	// _compute_lead_count: count leads assigned to this member this month.
	// Mirrors: odoo/addons/crm/models/crm_team_member.py _compute_lead_month_count
	m.RegisterCompute("lead_month_count", func(rs *orm.Recordset) (orm.Values, error) {
		env := rs.Env()
		memberID := rs.IDs()[0]

		var userID, teamID int64
		_ = env.Tx().QueryRow(env.Ctx(),
			`SELECT user_id, crm_team_id FROM crm_team_member WHERE id = $1`, memberID,
		).Scan(&userID, &teamID)

		var count int64
		_ = env.Tx().QueryRow(env.Ctx(),
			`SELECT COUNT(*) FROM crm_lead
			 WHERE user_id = $1 AND team_id = $2 AND active = true
			   AND create_date >= date_trunc('month', CURRENT_DATE)`,
			userID, teamID,
		).Scan(&count)

		return orm.Values{"lead_month_count": count}, nil
	})

	// SQL constraint: one member per team
	m.AddSQLConstraint(
		"unique_member_per_team",
		"UNIQUE(crm_team_id, user_id)",
		"A user can only be a member of a team once.",
	)
}
