package whistleblower

import (
	"context"
	"time"

	"github.com/google/uuid"
)

// ============================================================================
// Message Operations
// ============================================================================

// AddMessage adds an anonymous message to a report
func (s *Store) AddMessage(ctx context.Context, msg *AnonymousMessage) error {
	msg.ID = uuid.New()
	msg.SentAt = time.Now().UTC()

	_, err := s.pool.Exec(ctx, `
		INSERT INTO whistleblower_messages (
			id, report_id, direction, content, sent_at, read_at
		) VALUES (
			$1, $2, $3, $4, $5, $6
		)
	`,
		msg.ID, msg.ReportID, string(msg.Direction), msg.Content, msg.SentAt, msg.ReadAt,
	)

	return err
}

// ListMessages lists messages for a report
func (s *Store) ListMessages(ctx context.Context, reportID uuid.UUID) ([]AnonymousMessage, error) {
	rows, err := s.pool.Query(ctx, `
		SELECT
			id, report_id, direction, content, sent_at, read_at
		FROM whistleblower_messages WHERE report_id = $1
		ORDER BY sent_at ASC
	`, reportID)
	if err != nil {
		return nil, err
	}
	defer rows.Close()

	var messages []AnonymousMessage
	for rows.Next() {
		var msg AnonymousMessage
		var direction string

		err := rows.Scan(
			&msg.ID, &msg.ReportID, &direction, &msg.Content, &msg.SentAt, &msg.ReadAt,
		)
		if err != nil {
			return nil, err
		}

		msg.Direction = MessageDirection(direction)
		messages = append(messages, msg)
	}

	return messages, nil
}

// ============================================================================
// Measure Operations
// ============================================================================

// AddMeasure adds a corrective measure to a report
func (s *Store) AddMeasure(ctx context.Context, measure *Measure) error {
	measure.ID = uuid.New()
	measure.CreatedAt = time.Now().UTC()
	if measure.Status == "" {
		measure.Status = MeasureStatusPlanned
	}

	_, err := s.pool.Exec(ctx, `
		INSERT INTO whistleblower_measures (
			id, report_id, title, description, status,
			responsible, due_date, completed_at, created_at
		) VALUES (
			$1, $2, $3, $4, $5,
			$6, $7, $8, $9
		)
	`,
		measure.ID, measure.ReportID, measure.Title, measure.Description, string(measure.Status),
		measure.Responsible, measure.DueDate, measure.CompletedAt, measure.CreatedAt,
	)

	return err
}

// ListMeasures lists measures for a report
func (s *Store) ListMeasures(ctx context.Context, reportID uuid.UUID) ([]Measure, error) {
	rows, err := s.pool.Query(ctx, `
		SELECT
			id, report_id, title, description, status,
			responsible, due_date, completed_at, created_at
		FROM whistleblower_measures WHERE report_id = $1
		ORDER BY created_at ASC
	`, reportID)
	if err != nil {
		return nil, err
	}
	defer rows.Close()

	var measures []Measure
	for rows.Next() {
		var m Measure
		var status string

		err := rows.Scan(
			&m.ID, &m.ReportID, &m.Title, &m.Description, &status,
			&m.Responsible, &m.DueDate, &m.CompletedAt, &m.CreatedAt,
		)
		if err != nil {
			return nil, err
		}

		m.Status = MeasureStatus(status)
		measures = append(measures, m)
	}

	return measures, nil
}

// UpdateMeasure updates a measure
func (s *Store) UpdateMeasure(ctx context.Context, measure *Measure) error {
	_, err := s.pool.Exec(ctx, `
		UPDATE whistleblower_measures SET
			title = $2, description = $3, status = $4,
			responsible = $5, due_date = $6, completed_at = $7
		WHERE id = $1
	`,
		measure.ID,
		measure.Title, measure.Description, string(measure.Status),
		measure.Responsible, measure.DueDate, measure.CompletedAt,
	)

	return err
}

// ============================================================================
// Statistics
// ============================================================================

// GetStatistics returns aggregated whistleblower statistics for a tenant
func (s *Store) GetStatistics(ctx context.Context, tenantID uuid.UUID) (*WhistleblowerStatistics, error) {
	stats := &WhistleblowerStatistics{
		ByStatus:   make(map[string]int),
		ByCategory: make(map[string]int),
	}

	s.pool.QueryRow(ctx,
		"SELECT COUNT(*) FROM whistleblower_reports WHERE tenant_id = $1",
		tenantID).Scan(&stats.TotalReports)

	rows, err := s.pool.Query(ctx,
		"SELECT status, COUNT(*) FROM whistleblower_reports WHERE tenant_id = $1 GROUP BY status",
		tenantID)
	if err == nil {
		defer rows.Close()
		for rows.Next() {
			var status string
			var count int
			rows.Scan(&status, &count)
			stats.ByStatus[status] = count
		}
	}

	rows, err = s.pool.Query(ctx,
		"SELECT category, COUNT(*) FROM whistleblower_reports WHERE tenant_id = $1 GROUP BY category",
		tenantID)
	if err == nil {
		defer rows.Close()
		for rows.Next() {
			var category string
			var count int
			rows.Scan(&category, &count)
			stats.ByCategory[category] = count
		}
	}

	s.pool.QueryRow(ctx, `
		SELECT COUNT(*) FROM whistleblower_reports
		WHERE tenant_id = $1
			AND acknowledged_at IS NULL
			AND status = 'new'
			AND deadline_acknowledgment < NOW()
	`, tenantID).Scan(&stats.OverdueAcknowledgments)

	s.pool.QueryRow(ctx, `
		SELECT COUNT(*) FROM whistleblower_reports
		WHERE tenant_id = $1
			AND closed_at IS NULL
			AND status NOT IN ('closed', 'rejected')
			AND deadline_feedback < NOW()
	`, tenantID).Scan(&stats.OverdueFeedbacks)

	s.pool.QueryRow(ctx, `
		SELECT COALESCE(AVG(EXTRACT(EPOCH FROM (closed_at - received_at)) / 86400), 0)
		FROM whistleblower_reports
		WHERE tenant_id = $1 AND closed_at IS NOT NULL
	`, tenantID).Scan(&stats.AvgResolutionDays)

	return stats, nil
}

// ============================================================================
// Sequence Number
// ============================================================================

// GetNextSequenceNumber gets and increments the sequence number for reference number generation
func (s *Store) GetNextSequenceNumber(ctx context.Context, tenantID uuid.UUID, year int) (int, error) {
	var seq int

	err := s.pool.QueryRow(ctx, `
		INSERT INTO whistleblower_sequences (tenant_id, year, last_sequence)
		VALUES ($1, $2, 1)
		ON CONFLICT (tenant_id, year) DO UPDATE SET
			last_sequence = whistleblower_sequences.last_sequence + 1
		RETURNING last_sequence
	`, tenantID, year).Scan(&seq)

	if err != nil {
		return 0, err
	}

	return seq, nil
}
