package models

import (
	"fmt"
	"time"

	"odoo-go/pkg/orm"
)

// initProjectTimesheetExtension extends account.analytic.line with project/timesheet fields.
// In Odoo, timesheets are account.analytic.line records with project_id set.
// Mirrors: odoo/addons/hr_timesheet/models/hr_timesheet.py
//
//	class AccountAnalyticLine(models.Model):
//	    _inherit = 'account.analytic.line'
func initProjectTimesheetExtension() {
	al := orm.ExtendModel("account.analytic.line")

	al.AddFields(
		orm.Many2one("project_id", "project.project", orm.FieldOpts{
			String: "Project", Index: true,
		}),
		orm.Many2one("task_id", "project.task", orm.FieldOpts{
			String: "Task", Index: true,
		}),
		orm.Many2one("employee_id", "hr.employee", orm.FieldOpts{
			String: "Employee", Index: true,
		}),
		orm.Float("unit_amount", orm.FieldOpts{String: "Duration (Hours)"}),
		orm.Many2one("user_id", "res.users", orm.FieldOpts{String: "User"}),
		orm.Many2one("department_id", "hr.department", orm.FieldOpts{String: "Department"}),
		orm.Selection("encoding_uom_id", []orm.SelectionItem{
			{Value: "hours", Label: "Hours"},
			{Value: "days", Label: "Days"},
		}, orm.FieldOpts{String: "Encoding UoM", Default: "hours"}),
	)

	// DefaultGet: set date to today, employee from current user
	al.DefaultGet = func(env *orm.Environment, fields []string) orm.Values {
		vals := make(orm.Values)
		vals["date"] = time.Now().Format("2006-01-02")
		if env.UID() > 0 {
			vals["user_id"] = env.UID()
			// Try to find the employee linked to this user
			var empID int64
			err := env.Tx().QueryRow(env.Ctx(),
				`SELECT id FROM hr_employee WHERE user_id = $1 LIMIT 1`, env.UID()).Scan(&empID)
			if err == nil && empID > 0 {
				vals["employee_id"] = empID
				// Also set department
				var deptID int64
				env.Tx().QueryRow(env.Ctx(),
					`SELECT department_id FROM hr_employee WHERE id = $1`, empID).Scan(&deptID)
				if deptID > 0 {
					vals["department_id"] = deptID
				}
			}
		}
		return vals
	}
}

// initTimesheetReport registers a transient model for timesheet reporting.
// Mirrors: odoo/addons/hr_timesheet/report/hr_timesheet_report.py
func initTimesheetReport() {
	m := orm.NewModel("hr.timesheet.report", orm.ModelOpts{
		Description: "Timesheet 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("project_id", "project.project", orm.FieldOpts{String: "Project"}),
		orm.Many2one("employee_id", "hr.employee", orm.FieldOpts{String: "Employee"}),
		orm.Many2one("task_id", "project.task", orm.FieldOpts{String: "Task"}),
	)

	// get_timesheet_data: Aggregated timesheet data for reporting.
	// Returns: { by_project, by_employee, by_task, summary }
	m.RegisterMethod("get_timesheet_data", func(rs *orm.Recordset, args ...interface{}) (interface{}, error) {
		env := rs.Env()

		// ── Hours by project ──
		projRows, err := env.Tx().Query(env.Ctx(), `
			SELECT COALESCE(pp.name, 'No Project') AS project,
				SUM(aal.unit_amount) AS hours,
				COUNT(*) AS entries
			FROM account_analytic_line aal
			LEFT JOIN project_project pp ON pp.id = aal.project_id
			WHERE aal.project_id IS NOT NULL
			GROUP BY pp.name
			ORDER BY hours DESC
			LIMIT 20`)
		if err != nil {
			return nil, fmt.Errorf("timesheet_report: by project query: %w", err)
		}
		defer projRows.Close()

		var byProject []map[string]interface{}
		for projRows.Next() {
			var name string
			var hours float64
			var entries int64
			if err := projRows.Scan(&name, &hours, &entries); err != nil {
				continue
			}
			byProject = append(byProject, map[string]interface{}{
				"project": name,
				"hours":   hours,
				"entries": entries,
			})
		}

		// ── Hours by employee ──
		empRows, err := env.Tx().Query(env.Ctx(), `
			SELECT COALESCE(he.name, 'Unknown') AS employee,
				SUM(aal.unit_amount) AS hours,
				COUNT(*) AS entries,
				COUNT(DISTINCT aal.project_id) AS projects
			FROM account_analytic_line aal
			LEFT JOIN hr_employee he ON he.id = aal.employee_id
			WHERE aal.project_id IS NOT NULL
			GROUP BY he.name
			ORDER BY hours DESC
			LIMIT 20`)
		if err != nil {
			return nil, fmt.Errorf("timesheet_report: by employee query: %w", err)
		}
		defer empRows.Close()

		var byEmployee []map[string]interface{}
		for empRows.Next() {
			var name string
			var hours float64
			var entries, projects int64
			if err := empRows.Scan(&name, &hours, &entries, &projects); err != nil {
				continue
			}
			byEmployee = append(byEmployee, map[string]interface{}{
				"employee": name,
				"hours":    hours,
				"entries":  entries,
				"projects": projects,
			})
		}

		// ── Hours by task ──
		taskRows, err := env.Tx().Query(env.Ctx(), `
			SELECT COALESCE(pt.name, 'No Task') AS task,
				COALESCE(pp.name, 'No Project') AS project,
				SUM(aal.unit_amount) AS hours,
				COUNT(*) AS entries
			FROM account_analytic_line aal
			LEFT JOIN project_task pt ON pt.id = aal.task_id
			LEFT JOIN project_project pp ON pp.id = aal.project_id
			WHERE aal.project_id IS NOT NULL AND aal.task_id IS NOT NULL
			GROUP BY pt.name, pp.name
			ORDER BY hours DESC
			LIMIT 20`)
		if err != nil {
			return nil, fmt.Errorf("timesheet_report: by task query: %w", err)
		}
		defer taskRows.Close()

		var byTask []map[string]interface{}
		for taskRows.Next() {
			var taskName, projName string
			var hours float64
			var entries int64
			if err := taskRows.Scan(&taskName, &projName, &hours, &entries); err != nil {
				continue
			}
			byTask = append(byTask, map[string]interface{}{
				"task":    taskName,
				"project": projName,
				"hours":   hours,
				"entries": entries,
			})
		}

		// ── Summary ──
		var totalHours float64
		var totalEntries int64
		env.Tx().QueryRow(env.Ctx(), `
			SELECT COALESCE(SUM(unit_amount), 0), COUNT(*)
			FROM account_analytic_line WHERE project_id IS NOT NULL
		`).Scan(&totalHours, &totalEntries)

		return map[string]interface{}{
			"by_project":  byProject,
			"by_employee": byEmployee,
			"by_task":     byTask,
			"summary": map[string]interface{}{
				"total_hours":   totalHours,
				"total_entries": totalEntries,
			},
		}, nil
	})

	// get_timesheet_by_week: Weekly breakdown of timesheet hours.
	m.RegisterMethod("get_timesheet_by_week", func(rs *orm.Recordset, args ...interface{}) (interface{}, error) {
		env := rs.Env()

		rows, err := env.Tx().Query(env.Ctx(), `
			SELECT date_trunc('week', aal.date) AS week,
				SUM(aal.unit_amount) AS hours,
				COUNT(*) AS entries,
				COUNT(DISTINCT aal.employee_id) AS employees
			FROM account_analytic_line aal
			WHERE aal.project_id IS NOT NULL
			GROUP BY week
			ORDER BY week DESC
			LIMIT 12`)
		if err != nil {
			return nil, fmt.Errorf("timesheet_report: weekly query: %w", err)
		}
		defer rows.Close()

		var results []map[string]interface{}
		for rows.Next() {
			var week time.Time
			var hours float64
			var entries, employees int64
			if err := rows.Scan(&week, &hours, &entries, &employees); err != nil {
				continue
			}
			results = append(results, map[string]interface{}{
				"week":      week.Format("2006-01-02"),
				"hours":     hours,
				"entries":   entries,
				"employees": employees,
			})
		}
		return results, nil
	})
}
