package models

import (
	"fmt"
	"os"

	"odoo-go/pkg/orm"
	"odoo-go/pkg/tools"
)

var calendarClient *tools.APIClient

func getCalendarClient() *tools.APIClient {
	if calendarClient != nil {
		return calendarClient
	}
	apiKey := os.Getenv("GOOGLE_CALENDAR_API_KEY")
	if apiKey == "" {
		return nil
	}
	calendarClient = tools.NewAPIClient("https://www.googleapis.com", apiKey)
	return calendarClient
}

// initCalendarEvent registers the calendar.event model.
// Mirrors: odoo/addons/calendar/models/calendar_event.py
func initCalendarEvent() {
	m := orm.NewModel("calendar.event", orm.ModelOpts{
		Description: "Calendar Event",
		Order:       "start desc",
	})

	m.AddFields(
		orm.Char("name", orm.FieldOpts{String: "Meeting Subject", Required: true}),
		orm.Datetime("start", orm.FieldOpts{String: "Start", Required: true}),
		orm.Datetime("stop", orm.FieldOpts{String: "Stop", Required: true}),
		orm.Boolean("allday", orm.FieldOpts{String: "All Day"}),
		orm.Text("description", orm.FieldOpts{String: "Description"}),
		orm.Char("location", orm.FieldOpts{String: "Location"}),
		orm.Many2one("user_id", "res.users", orm.FieldOpts{String: "Organizer"}),
		orm.Many2one("partner_id", "res.partner", orm.FieldOpts{String: "Contact"}),
		orm.Many2many("attendee_ids", "res.partner", orm.FieldOpts{String: "Attendees"}),
		orm.Many2one("company_id", "res.company", orm.FieldOpts{String: "Company"}),
		orm.Boolean("active", orm.FieldOpts{String: "Active", Default: true}),
		orm.Selection("state", []orm.SelectionItem{
			{Value: "draft", Label: "Unconfirmed"},
			{Value: "open", Label: "Confirmed"},
			{Value: "done", Label: "Done"},
			{Value: "cancel", Label: "Cancelled"},
		}, orm.FieldOpts{String: "Status", Default: "draft"}),
		// Google sync fields
		orm.Char("google_event_id", orm.FieldOpts{String: "Google Event ID", Index: true}),
		orm.Char("google_calendar_id", orm.FieldOpts{String: "Google Calendar ID"}),
		orm.Datetime("google_synced_at", orm.FieldOpts{String: "Last Synced"}),
	)
}

// initGoogleCalendarSync registers sync methods.
func initGoogleCalendarSync() {
	event := orm.Registry.Get("calendar.event")
	if event == nil {
		return
	}

	// push_to_google: Create/update event in Google Calendar
	event.RegisterMethod("push_to_google", func(rs *orm.Recordset, args ...interface{}) (interface{}, error) {
		client := getCalendarClient()
		if client == nil {
			return nil, fmt.Errorf("google_calendar: GOOGLE_CALENDAR_API_KEY not configured")
		}

		env := rs.Env()
		calendarID := "primary"
		if len(args) > 0 {
			if cid, ok := args[0].(string); ok && cid != "" {
				calendarID = cid
			}
		}

		for _, id := range rs.IDs() {
			var name, description, location, googleEventID string
			var start, stop string
			env.Tx().QueryRow(env.Ctx(),
				`SELECT COALESCE(name,''), COALESCE(description,''), COALESCE(location,''),
				 COALESCE(google_event_id,''), COALESCE(start::text,''), COALESCE(stop::text,'')
				 FROM calendar_event WHERE id = $1`, id,
			).Scan(&name, &description, &location, &googleEventID, &start, &stop)

			eventBody := map[string]interface{}{
				"summary":     name,
				"description": description,
				"location":    location,
				"start": map[string]string{
					"dateTime": start,
					"timeZone": "Europe/Berlin",
				},
				"end": map[string]string{
					"dateTime": stop,
					"timeZone": "Europe/Berlin",
				},
			}

			if googleEventID != "" {
				// Update existing
				var result map[string]interface{}
				err := client.PostJSON(
					fmt.Sprintf("/calendar/v3/calendars/%s/events/%s", calendarID, googleEventID),
					nil, eventBody, &result,
				)
				if err != nil {
					return nil, fmt.Errorf("google_calendar: update event %d: %w", id, err)
				}
			} else {
				// Create new
				var result struct {
					ID string `json:"id"`
				}
				err := client.PostJSON(
					fmt.Sprintf("/calendar/v3/calendars/%s/events", calendarID),
					nil, eventBody, &result,
				)
				if err != nil {
					return nil, fmt.Errorf("google_calendar: create event %d: %w", id, err)
				}
				// Store Google event ID
				env.Tx().Exec(env.Ctx(),
					`UPDATE calendar_event SET google_event_id = $1, google_synced_at = NOW() WHERE id = $2`,
					result.ID, id)
			}
		}
		return true, nil
	})

	// pull_from_google: Fetch events from Google Calendar
	event.RegisterMethod("pull_from_google", func(rs *orm.Recordset, args ...interface{}) (interface{}, error) {
		client := getCalendarClient()
		if client == nil {
			return nil, fmt.Errorf("google_calendar: GOOGLE_CALENDAR_API_KEY not configured")
		}

		calendarID := "primary"
		if len(args) > 0 {
			if cid, ok := args[0].(string); ok && cid != "" {
				calendarID = cid
			}
		}

		var result GoogleEventsResponse
		err := client.GetJSON(
			fmt.Sprintf("/calendar/v3/calendars/%s/events", calendarID),
			map[string]string{
				"maxResults":   "50",
				"singleEvents": "true",
				"orderBy":      "startTime",
				"timeMin":      "2026-01-01T00:00:00Z",
			},
			&result,
		)
		if err != nil {
			return nil, fmt.Errorf("google_calendar: fetch events: %w", err)
		}

		env := rs.Env()
		imported := 0
		for _, ge := range result.Items {
			// Check if already synced
			var existing int
			env.Tx().QueryRow(env.Ctx(),
				`SELECT COUNT(*) FROM calendar_event WHERE google_event_id = $1`, ge.ID,
			).Scan(&existing)

			if existing > 0 {
				continue // Already imported
			}

			startTime := ge.Start.DateTime
			if startTime == "" {
				startTime = ge.Start.Date
			}
			endTime := ge.End.DateTime
			if endTime == "" {
				endTime = ge.End.Date
			}

			eventRS := env.Model("calendar.event")
			_, err := eventRS.Create(orm.Values{
				"name":             ge.Summary,
				"description":      ge.Description,
				"location":         ge.Location,
				"start":            startTime,
				"stop":             endTime,
				"google_event_id":  ge.ID,
				"google_synced_at": "now",
				"state":            "open",
			})
			if err == nil {
				imported++
			}
		}

		return map[string]interface{}{
			"imported": imported,
			"total":    len(result.Items),
		}, nil
	})
}

// --- Google Calendar API Response Types ---

type GoogleEventsResponse struct {
	Items []GoogleEvent `json:"items"`
}

type GoogleEvent struct {
	ID          string `json:"id"`
	Summary     string `json:"summary"`
	Description string `json:"description"`
	Location    string `json:"location"`
	Start       struct {
		DateTime string `json:"dateTime"`
		Date     string `json:"date"`
	} `json:"start"`
	End struct {
		DateTime string `json:"dateTime"`
		Date     string `json:"date"`
	} `json:"end"`
}
