package services

import (
	"context"
	"fmt"
	"time"

	"github.com/google/uuid"
	"github.com/jmoiron/sqlx"

	"mgit.msbls.de/m/KanzlAI-mGMT/internal/models"
)

type AppointmentService struct {
	db    *sqlx.DB
	audit *AuditService
}

func NewAppointmentService(db *sqlx.DB, audit *AuditService) *AppointmentService {
	return &AppointmentService{db: db, audit: audit}
}

type AppointmentFilter struct {
	CaseID    *uuid.UUID
	Type      *string
	StartFrom *time.Time
	StartTo   *time.Time
}

func (s *AppointmentService) List(ctx context.Context, tenantID uuid.UUID, filter AppointmentFilter) ([]models.Appointment, error) {
	query := "SELECT * FROM appointments WHERE tenant_id = $1"
	args := []any{tenantID}
	argN := 2

	if filter.CaseID != nil {
		query += fmt.Sprintf(" AND case_id = $%d", argN)
		args = append(args, *filter.CaseID)
		argN++
	}
	if filter.Type != nil {
		query += fmt.Sprintf(" AND appointment_type = $%d", argN)
		args = append(args, *filter.Type)
		argN++
	}
	if filter.StartFrom != nil {
		query += fmt.Sprintf(" AND start_at >= $%d", argN)
		args = append(args, *filter.StartFrom)
		argN++
	}
	if filter.StartTo != nil {
		query += fmt.Sprintf(" AND start_at <= $%d", argN)
		args = append(args, *filter.StartTo)
		argN++
	}

	query += " ORDER BY start_at ASC"

	var appointments []models.Appointment
	if err := s.db.SelectContext(ctx, &appointments, query, args...); err != nil {
		return nil, fmt.Errorf("listing appointments: %w", err)
	}
	if appointments == nil {
		appointments = []models.Appointment{}
	}
	return appointments, nil
}

func (s *AppointmentService) GetByID(ctx context.Context, tenantID, id uuid.UUID) (*models.Appointment, error) {
	var a models.Appointment
	err := s.db.GetContext(ctx, &a, "SELECT * FROM appointments WHERE id = $1 AND tenant_id = $2", id, tenantID)
	if err != nil {
		return nil, fmt.Errorf("getting appointment: %w", err)
	}
	return &a, nil
}

func (s *AppointmentService) Create(ctx context.Context, a *models.Appointment) error {
	a.ID = uuid.New()
	now := time.Now().UTC()
	a.CreatedAt = now
	a.UpdatedAt = now

	_, err := s.db.NamedExecContext(ctx, `
		INSERT INTO appointments (id, tenant_id, case_id, title, description, start_at, end_at, location, appointment_type, caldav_uid, caldav_etag, created_at, updated_at)
		VALUES (:id, :tenant_id, :case_id, :title, :description, :start_at, :end_at, :location, :appointment_type, :caldav_uid, :caldav_etag, :created_at, :updated_at)
	`, a)
	if err != nil {
		return fmt.Errorf("creating appointment: %w", err)
	}
	s.audit.Log(ctx, "create", "appointment", &a.ID, nil, a)
	return nil
}

func (s *AppointmentService) Update(ctx context.Context, a *models.Appointment) error {
	a.UpdatedAt = time.Now().UTC()

	result, err := s.db.NamedExecContext(ctx, `
		UPDATE appointments SET
			case_id = :case_id,
			title = :title,
			description = :description,
			start_at = :start_at,
			end_at = :end_at,
			location = :location,
			appointment_type = :appointment_type,
			caldav_uid = :caldav_uid,
			caldav_etag = :caldav_etag,
			updated_at = :updated_at
		WHERE id = :id AND tenant_id = :tenant_id
	`, a)
	if err != nil {
		return fmt.Errorf("updating appointment: %w", err)
	}
	rows, err := result.RowsAffected()
	if err != nil {
		return fmt.Errorf("checking rows affected: %w", err)
	}
	if rows == 0 {
		return fmt.Errorf("appointment not found")
	}
	s.audit.Log(ctx, "update", "appointment", &a.ID, nil, a)
	return nil
}

func (s *AppointmentService) Delete(ctx context.Context, tenantID, id uuid.UUID) error {
	result, err := s.db.ExecContext(ctx, "DELETE FROM appointments WHERE id = $1 AND tenant_id = $2", id, tenantID)
	if err != nil {
		return fmt.Errorf("deleting appointment: %w", err)
	}
	rows, err := result.RowsAffected()
	if err != nil {
		return fmt.Errorf("checking rows affected: %w", err)
	}
	if rows == 0 {
		return fmt.Errorf("appointment not found")
	}
	s.audit.Log(ctx, "delete", "appointment", &id, nil, nil)
	return nil
}
