package mail

import (
	"context"
	"encoding/json"
	"strings"

	"github.com/jackc/pgx/v5"
)

func (s *Service) GetMailSettings(ctx context.Context, externalID string) (MailSettings, error) {
	defaults := defaultMailSettings()

	var density, themeMode, backgroundID, inboxSort, readingPane *string
	var conversationMode *bool
	var notificationsJSON []byte
	var updatedAt any

	err := s.db.QueryRow(ctx, `
		SELECT
			s.preferences->'mail'->>'density',
			s.preferences->'mail'->>'theme_mode',
			s.preferences->'mail'->>'background_id',
			s.preferences->'mail'->>'inbox_sort',
			s.preferences->'mail'->>'reading_pane',
			(s.preferences->'mail'->>'conversation_mode')::boolean,
			s.preferences->'mail'->'notifications',
			s.updated_at
		FROM users u
		LEFT JOIN settings s ON s.user_id = u.id
		WHERE u.external_id = $1
	`, externalID).Scan(&density, &themeMode, &backgroundID, &inboxSort, &readingPane, &conversationMode, &notificationsJSON, &updatedAt)
	if err != nil {
		if err == pgx.ErrNoRows {
			return defaults, nil
		}
		return MailSettings{}, err
	}

	if density != nil && *density != "" {
		defaults.Density = *density
	}
	if themeMode != nil && *themeMode != "" {
		defaults.ThemeMode = *themeMode
	}
	if backgroundID != nil && *backgroundID != "" {
		defaults.BackgroundID = *backgroundID
	}
	if inboxSort != nil && *inboxSort != "" {
		defaults.InboxSort = *inboxSort
	}
	if readingPane != nil && *readingPane != "" {
		defaults.ReadingPane = *readingPane
	}
	if conversationMode != nil {
		defaults.ConversationMode = *conversationMode
	}
	if len(notificationsJSON) > 0 && string(notificationsJSON) != "null" {
		var n MailNotificationSettings
		if err := json.Unmarshal(notificationsJSON, &n); err == nil {
			defaults.Notifications = n
		}
	}
	if updatedAt != nil {
		defaults.UpdatedAt = updatedAt
	}
	return defaults, nil
}

func (s *Service) UpdateMailSettings(ctx context.Context, externalID string, req *patchMailSettingsRequest) (MailSettings, error) {
	patch := map[string]any{}
	if req.Density != nil {
		patch["density"] = strings.ToLower(strings.TrimSpace(*req.Density))
	}
	if req.ThemeMode != nil {
		patch["theme_mode"] = strings.ToLower(strings.TrimSpace(*req.ThemeMode))
	}
	if req.BackgroundID != nil {
		patch["background_id"] = strings.ToLower(strings.TrimSpace(*req.BackgroundID))
	}
	if req.InboxSort != nil {
		patch["inbox_sort"] = strings.ToLower(strings.TrimSpace(*req.InboxSort))
	}
	if req.ReadingPane != nil {
		patch["reading_pane"] = strings.ToLower(strings.TrimSpace(*req.ReadingPane))
	}
	if req.ConversationMode != nil {
		patch["conversation_mode"] = *req.ConversationMode
	}
	if req.Notifications != nil {
		current, err := s.GetMailSettings(ctx, externalID)
		if err != nil {
			return MailSettings{}, err
		}
		merged := current.Notifications
		if req.Notifications.DesktopNewMail != nil {
			merged.DesktopNewMail = *req.Notifications.DesktopNewMail
		}
		if req.Notifications.DesktopMentions != nil {
			merged.DesktopMentions = *req.Notifications.DesktopMentions
		}
		if req.Notifications.EmailDigest != nil {
			merged.EmailDigest = *req.Notifications.EmailDigest
		}
		if req.Notifications.SoundEnabled != nil {
			merged.SoundEnabled = *req.Notifications.SoundEnabled
		}
		patch["notifications"] = merged
	}

	patchJSON, err := json.Marshal(patch)
	if err != nil {
		return MailSettings{}, err
	}

	var updatedAt any
	err = s.db.QueryRow(ctx, `
		INSERT INTO settings (user_id, preferences)
		VALUES (
			(SELECT id FROM users WHERE external_id = $1),
			jsonb_build_object('mail', $2::jsonb)
		)
		ON CONFLICT (user_id) DO UPDATE SET
			preferences = jsonb_set(
				COALESCE(settings.preferences, '{}'::jsonb),
				'{mail}',
				COALESCE(settings.preferences->'mail', '{}'::jsonb) || $2::jsonb
			),
			updated_at = NOW()
		RETURNING updated_at
	`, externalID, patchJSON).Scan(&updatedAt)
	if err != nil {
		return MailSettings{}, err
	}

	result, err := s.GetMailSettings(ctx, externalID)
	if err != nil {
		return MailSettings{}, err
	}
	result.UpdatedAt = updatedAt
	return result, nil
}
