package portfolio

import (
	"context"
	"fmt"
	"time"

	"github.com/google/uuid"
)

// ============================================================================
// Metrics and Statistics
// ============================================================================

// RecalculateMetrics recalculates aggregated metrics for a portfolio
func (s *Store) RecalculateMetrics(ctx context.Context, portfolioID uuid.UUID) error {
	// Count by type
	var totalAssessments, totalRoadmaps, totalWorkshops int
	s.pool.QueryRow(ctx,
		"SELECT COUNT(*) FROM portfolio_items WHERE portfolio_id = $1 AND item_type = 'ASSESSMENT'",
		portfolioID).Scan(&totalAssessments)
	s.pool.QueryRow(ctx,
		"SELECT COUNT(*) FROM portfolio_items WHERE portfolio_id = $1 AND item_type = 'ROADMAP'",
		portfolioID).Scan(&totalRoadmaps)
	s.pool.QueryRow(ctx,
		"SELECT COUNT(*) FROM portfolio_items WHERE portfolio_id = $1 AND item_type = 'WORKSHOP'",
		portfolioID).Scan(&totalWorkshops)

	// Calculate risk metrics from assessments
	var avgRiskScore float64
	var highRiskCount, conditionalCount, approvedCount int

	s.pool.QueryRow(ctx, `
		SELECT COALESCE(AVG(risk_score), 0)
		FROM portfolio_items
		WHERE portfolio_id = $1 AND item_type = 'ASSESSMENT'
	`, portfolioID).Scan(&avgRiskScore)

	s.pool.QueryRow(ctx, `
		SELECT COUNT(*)
		FROM portfolio_items
		WHERE portfolio_id = $1 AND item_type = 'ASSESSMENT' AND risk_level IN ('HIGH', 'UNACCEPTABLE')
	`, portfolioID).Scan(&highRiskCount)

	s.pool.QueryRow(ctx, `
		SELECT COUNT(*)
		FROM portfolio_items
		WHERE portfolio_id = $1 AND item_type = 'ASSESSMENT' AND feasibility = 'CONDITIONAL'
	`, portfolioID).Scan(&conditionalCount)

	s.pool.QueryRow(ctx, `
		SELECT COUNT(*)
		FROM portfolio_items
		WHERE portfolio_id = $1 AND item_type = 'ASSESSMENT' AND feasibility = 'YES'
	`, portfolioID).Scan(&approvedCount)

	// Calculate compliance score (simplified: % of approved items)
	var complianceScore float64
	if totalAssessments > 0 {
		complianceScore = (float64(approvedCount) / float64(totalAssessments)) * 100
	}

	// Update portfolio
	_, err := s.pool.Exec(ctx, `
		UPDATE portfolios SET
			total_assessments = $2,
			total_roadmaps = $3,
			total_workshops = $4,
			avg_risk_score = $5,
			high_risk_count = $6,
			conditional_count = $7,
			approved_count = $8,
			compliance_score = $9,
			updated_at = NOW()
		WHERE id = $1
	`,
		portfolioID,
		totalAssessments, totalRoadmaps, totalWorkshops,
		avgRiskScore, highRiskCount, conditionalCount, approvedCount,
		complianceScore,
	)

	return err
}

// GetPortfolioStats returns detailed statistics for a portfolio
func (s *Store) GetPortfolioStats(ctx context.Context, portfolioID uuid.UUID) (*PortfolioStats, error) {
	stats := &PortfolioStats{
		ItemsByType: make(map[ItemType]int),
	}

	// Total items
	s.pool.QueryRow(ctx,
		"SELECT COUNT(*) FROM portfolio_items WHERE portfolio_id = $1",
		portfolioID).Scan(&stats.TotalItems)

	// Items by type
	rows, _ := s.pool.Query(ctx, `
		SELECT item_type, COUNT(*)
		FROM portfolio_items
		WHERE portfolio_id = $1
		GROUP BY item_type
	`, portfolioID)
	if rows != nil {
		defer rows.Close()
		for rows.Next() {
			var itemType string
			var count int
			rows.Scan(&itemType, &count)
			stats.ItemsByType[ItemType(itemType)] = count
		}
	}

	// Risk distribution
	s.pool.QueryRow(ctx, `
		SELECT COUNT(*) FROM portfolio_items
		WHERE portfolio_id = $1 AND risk_level = 'MINIMAL'
	`, portfolioID).Scan(&stats.RiskDistribution.Minimal)

	s.pool.QueryRow(ctx, `
		SELECT COUNT(*) FROM portfolio_items
		WHERE portfolio_id = $1 AND risk_level = 'LOW'
	`, portfolioID).Scan(&stats.RiskDistribution.Low)

	s.pool.QueryRow(ctx, `
		SELECT COUNT(*) FROM portfolio_items
		WHERE portfolio_id = $1 AND risk_level = 'MEDIUM'
	`, portfolioID).Scan(&stats.RiskDistribution.Medium)

	s.pool.QueryRow(ctx, `
		SELECT COUNT(*) FROM portfolio_items
		WHERE portfolio_id = $1 AND risk_level = 'HIGH'
	`, portfolioID).Scan(&stats.RiskDistribution.High)

	s.pool.QueryRow(ctx, `
		SELECT COUNT(*) FROM portfolio_items
		WHERE portfolio_id = $1 AND risk_level = 'UNACCEPTABLE'
	`, portfolioID).Scan(&stats.RiskDistribution.Unacceptable)

	// Feasibility distribution
	s.pool.QueryRow(ctx, `
		SELECT COUNT(*) FROM portfolio_items
		WHERE portfolio_id = $1 AND feasibility = 'YES'
	`, portfolioID).Scan(&stats.FeasibilityDist.Yes)

	s.pool.QueryRow(ctx, `
		SELECT COUNT(*) FROM portfolio_items
		WHERE portfolio_id = $1 AND feasibility = 'CONDITIONAL'
	`, portfolioID).Scan(&stats.FeasibilityDist.Conditional)

	s.pool.QueryRow(ctx, `
		SELECT COUNT(*) FROM portfolio_items
		WHERE portfolio_id = $1 AND feasibility = 'NO'
	`, portfolioID).Scan(&stats.FeasibilityDist.No)

	// Average risk score
	s.pool.QueryRow(ctx, `
		SELECT COALESCE(AVG(risk_score), 0)
		FROM portfolio_items
		WHERE portfolio_id = $1 AND item_type = 'ASSESSMENT'
	`, portfolioID).Scan(&stats.AvgRiskScore)

	// Compliance score
	s.pool.QueryRow(ctx,
		"SELECT compliance_score FROM portfolios WHERE id = $1",
		portfolioID).Scan(&stats.ComplianceScore)

	// DSFA required count — estimate from high risk items
	stats.DSFARequired = stats.RiskDistribution.High + stats.RiskDistribution.Unacceptable

	// Controls required (items with CONDITIONAL feasibility)
	stats.ControlsRequired = stats.FeasibilityDist.Conditional

	stats.LastUpdated = time.Now().UTC()

	return stats, nil
}

// GetPortfolioSummary returns a complete portfolio summary
func (s *Store) GetPortfolioSummary(ctx context.Context, portfolioID uuid.UUID) (*PortfolioSummary, error) {
	portfolio, err := s.GetPortfolio(ctx, portfolioID)
	if err != nil || portfolio == nil {
		return nil, err
	}

	items, err := s.ListItems(ctx, portfolioID, nil)
	if err != nil {
		return nil, err
	}

	stats, err := s.GetPortfolioStats(ctx, portfolioID)
	if err != nil {
		return nil, err
	}

	return &PortfolioSummary{
		Portfolio:        portfolio,
		Items:            items,
		RiskDistribution: stats.RiskDistribution,
		FeasibilityDist:  stats.FeasibilityDist,
	}, nil
}

// ============================================================================
// Bulk Operations
// ============================================================================

// BulkAddItems adds multiple items to a portfolio
func (s *Store) BulkAddItems(ctx context.Context, portfolioID uuid.UUID, items []PortfolioItem, userID uuid.UUID) (*BulkAddItemsResponse, error) {
	result := &BulkAddItemsResponse{
		Errors: []string{},
	}

	for _, item := range items {
		item.PortfolioID = portfolioID
		item.AddedBy = userID

		// Fetch item info from source table if not provided
		if item.Title == "" {
			s.populateItemInfo(ctx, &item)
		}

		if err := s.AddItem(ctx, &item); err != nil {
			result.Skipped++
			result.Errors = append(result.Errors, fmt.Sprintf("%s: %v", item.ItemID, err))
		} else {
			result.Added++
		}
	}

	return result, nil
}

// populateItemInfo fetches item metadata from the source table
func (s *Store) populateItemInfo(ctx context.Context, item *PortfolioItem) {
	switch item.ItemType {
	case ItemTypeAssessment:
		s.pool.QueryRow(ctx, `
			SELECT title, feasibility, risk_level, risk_score, status
			FROM ucca_assessments WHERE id = $1
		`, item.ItemID).Scan(&item.Title, &item.Feasibility, &item.RiskLevel, &item.RiskScore, &item.Status)

	case ItemTypeRoadmap:
		s.pool.QueryRow(ctx, `
			SELECT name, status
			FROM roadmaps WHERE id = $1
		`, item.ItemID).Scan(&item.Title, &item.Status)

	case ItemTypeWorkshop:
		s.pool.QueryRow(ctx, `
			SELECT title, status
			FROM workshop_sessions WHERE id = $1
		`, item.ItemID).Scan(&item.Title, &item.Status)
	}
}

// ============================================================================
// Activity Tracking
// ============================================================================

// LogActivity logs an activity entry for a portfolio
func (s *Store) LogActivity(ctx context.Context, portfolioID uuid.UUID, entry *ActivityEntry) error {
	_, err := s.pool.Exec(ctx, `
		INSERT INTO portfolio_activity (
			id, portfolio_id, timestamp, action,
			item_type, item_id, item_title, user_id
		) VALUES (
			$1, $2, $3, $4, $5, $6, $7, $8
		)
	`,
		uuid.New(), portfolioID, entry.Timestamp, entry.Action,
		string(entry.ItemType), entry.ItemID, entry.ItemTitle, entry.UserID,
	)
	return err
}

// GetRecentActivity retrieves recent activity for a portfolio
func (s *Store) GetRecentActivity(ctx context.Context, portfolioID uuid.UUID, limit int) ([]ActivityEntry, error) {
	if limit <= 0 {
		limit = 20
	}

	rows, err := s.pool.Query(ctx, `
		SELECT timestamp, action, item_type, item_id, item_title, user_id
		FROM portfolio_activity
		WHERE portfolio_id = $1
		ORDER BY timestamp DESC
		LIMIT $2
	`, portfolioID, limit)
	if err != nil {
		return nil, err
	}
	defer rows.Close()

	var activities []ActivityEntry
	for rows.Next() {
		var entry ActivityEntry
		var itemType string
		err := rows.Scan(
			&entry.Timestamp, &entry.Action, &itemType,
			&entry.ItemID, &entry.ItemTitle, &entry.UserID,
		)
		if err != nil {
			return nil, err
		}
		entry.ItemType = ItemType(itemType)
		activities = append(activities, entry)
	}

	return activities, nil
}
