package handlers

import (
	dbgen "Yimaru-Backend/gen/db"
	"Yimaru-Backend/internal/domain"
	"time"

	"github.com/gofiber/fiber/v2"
)

func toTime(v interface{}) time.Time {
	if t, ok := v.(time.Time); ok {
		return t
	}
	return time.Time{}
}

func (h *Handler) GetAnalyticsDashboard(c *fiber.Ctx) error {
	ctx := c.Context()

	// ── Users ──
	usersSummary, err := h.analyticsDB.AnalyticsUsersSummary(ctx)
	if err != nil {
		return fiber.NewError(fiber.StatusInternalServerError, "Failed to fetch user analytics")
	}
	usersByRole, err := h.analyticsDB.AnalyticsUsersByRole(ctx)
	if err != nil {
		return fiber.NewError(fiber.StatusInternalServerError, "Failed to fetch users by role")
	}
	usersByStatus, err := h.analyticsDB.AnalyticsUsersByStatus(ctx)
	if err != nil {
		return fiber.NewError(fiber.StatusInternalServerError, "Failed to fetch users by status")
	}
	usersByAge, err := h.analyticsDB.AnalyticsUsersByAgeGroup(ctx)
	if err != nil {
		return fiber.NewError(fiber.StatusInternalServerError, "Failed to fetch users by age group")
	}
	usersByKnowledge, err := h.analyticsDB.AnalyticsUsersByKnowledgeLevel(ctx)
	if err != nil {
		return fiber.NewError(fiber.StatusInternalServerError, "Failed to fetch users by knowledge level")
	}
	usersByRegion, err := h.analyticsDB.AnalyticsUsersByRegion(ctx)
	if err != nil {
		return fiber.NewError(fiber.StatusInternalServerError, "Failed to fetch users by region")
	}
	userRegs, err := h.analyticsDB.AnalyticsUserRegistrationsLast30Days(ctx)
	if err != nil {
		return fiber.NewError(fiber.StatusInternalServerError, "Failed to fetch user registrations")
	}

	// ── Subscriptions ──
	subsSummary, err := h.analyticsDB.AnalyticsSubscriptionsSummary(ctx)
	if err != nil {
		return fiber.NewError(fiber.StatusInternalServerError, "Failed to fetch subscription analytics")
	}
	subsByStatus, err := h.analyticsDB.AnalyticsSubscriptionsByStatus(ctx)
	if err != nil {
		return fiber.NewError(fiber.StatusInternalServerError, "Failed to fetch subscriptions by status")
	}
	revenueByPlan, err := h.analyticsDB.AnalyticsRevenueByPlan(ctx)
	if err != nil {
		return fiber.NewError(fiber.StatusInternalServerError, "Failed to fetch revenue by plan")
	}
	newSubs30, err := h.analyticsDB.AnalyticsNewSubscriptionsLast30Days(ctx)
	if err != nil {
		return fiber.NewError(fiber.StatusInternalServerError, "Failed to fetch new subscriptions last 30 days")
	}

	// ── Payments ──
	paymentsSummary, err := h.analyticsDB.AnalyticsPaymentsSummary(ctx)
	if err != nil {
		return fiber.NewError(fiber.StatusInternalServerError, "Failed to fetch payment analytics")
	}
	paymentsByStatus, err := h.analyticsDB.AnalyticsPaymentsByStatus(ctx)
	if err != nil {
		return fiber.NewError(fiber.StatusInternalServerError, "Failed to fetch payments by status")
	}
	paymentsByMethod, err := h.analyticsDB.AnalyticsPaymentsByMethod(ctx)
	if err != nil {
		return fiber.NewError(fiber.StatusInternalServerError, "Failed to fetch payments by method")
	}
	revenue30, err := h.analyticsDB.AnalyticsRevenueLast30Days(ctx)
	if err != nil {
		return fiber.NewError(fiber.StatusInternalServerError, "Failed to fetch revenue last 30 days")
	}

	// ── Courses ──
	courseCounts, err := h.analyticsDB.AnalyticsCourseCounts(ctx)
	if err != nil {
		return fiber.NewError(fiber.StatusInternalServerError, "Failed to fetch course analytics")
	}

	// ── Content ──
	questionsCounts, err := h.analyticsDB.AnalyticsQuestionsCounts(ctx)
	if err != nil {
		return fiber.NewError(fiber.StatusInternalServerError, "Failed to fetch content analytics")
	}
	questionsByType, err := h.analyticsDB.AnalyticsQuestionsByType(ctx)
	if err != nil {
		return fiber.NewError(fiber.StatusInternalServerError, "Failed to fetch questions by type")
	}
	questionSetsByType, err := h.analyticsDB.AnalyticsQuestionSetsByType(ctx)
	if err != nil {
		return fiber.NewError(fiber.StatusInternalServerError, "Failed to fetch question sets by type")
	}

	// ── Notifications ──
	notifSummary, err := h.analyticsDB.AnalyticsNotificationsSummary(ctx)
	if err != nil {
		return fiber.NewError(fiber.StatusInternalServerError, "Failed to fetch notification analytics")
	}
	notifByChannel, err := h.analyticsDB.AnalyticsNotificationsByChannel(ctx)
	if err != nil {
		return fiber.NewError(fiber.StatusInternalServerError, "Failed to fetch notifications by channel")
	}
	notifByType, err := h.analyticsDB.AnalyticsNotificationsByType(ctx)
	if err != nil {
		return fiber.NewError(fiber.StatusInternalServerError, "Failed to fetch notifications by type")
	}

	// ── Issues ──
	issuesSummary, err := h.analyticsDB.AnalyticsIssuesSummary(ctx)
	if err != nil {
		return fiber.NewError(fiber.StatusInternalServerError, "Failed to fetch issue analytics")
	}
	issuesByStatus, err := h.analyticsDB.AnalyticsIssuesByStatus(ctx)
	if err != nil {
		return fiber.NewError(fiber.StatusInternalServerError, "Failed to fetch issues by status")
	}
	issuesByType, err := h.analyticsDB.AnalyticsIssuesByType(ctx)
	if err != nil {
		return fiber.NewError(fiber.StatusInternalServerError, "Failed to fetch issues by type")
	}

	// ── Team ──
	teamTotal, err := h.analyticsDB.AnalyticsTeamSummary(ctx)
	if err != nil {
		return fiber.NewError(fiber.StatusInternalServerError, "Failed to fetch team analytics")
	}
	teamByRole, err := h.analyticsDB.AnalyticsTeamByRole(ctx)
	if err != nil {
		return fiber.NewError(fiber.StatusInternalServerError, "Failed to fetch team by role")
	}
	teamByStatus, err := h.analyticsDB.AnalyticsTeamByStatus(ctx)
	if err != nil {
		return fiber.NewError(fiber.StatusInternalServerError, "Failed to fetch team by status")
	}

	// ── Map to domain types ──
	dashboard := domain.AnalyticsDashboard{
		GeneratedAt: time.Now(),
		Users:       mapUsersSection(usersSummary, usersByRole, usersByStatus, usersByAge, usersByKnowledge, usersByRegion, userRegs),
		Subscriptions: mapSubscriptionsSection(subsSummary, subsByStatus, revenueByPlan, newSubs30),
		Payments:      mapPaymentsSection(paymentsSummary, paymentsByStatus, paymentsByMethod, revenue30),
		Courses: domain.AnalyticsCoursesSection{
			TotalCategories: courseCounts.TotalCategories,
			TotalCourses:    courseCounts.TotalCourses,
			TotalSubCourses: courseCounts.TotalSubCourses,
			TotalVideos:     courseCounts.TotalVideos,
		},
		Content:       mapContentSection(questionsCounts, questionsByType, questionSetsByType),
		Notifications: mapNotificationsSection(notifSummary, notifByChannel, notifByType),
		Issues:        mapIssuesSection(issuesSummary, issuesByStatus, issuesByType),
		Team:          mapTeamSection(teamTotal, teamByRole, teamByStatus),
	}

	return c.JSON(dashboard)
}

func mapUsersSection(
	summary dbgen.AnalyticsUsersSummaryRow,
	byRole []dbgen.AnalyticsUsersByRoleRow,
	byStatus []dbgen.AnalyticsUsersByStatusRow,
	byAge []dbgen.AnalyticsUsersByAgeGroupRow,
	byKnowledge []dbgen.AnalyticsUsersByKnowledgeLevelRow,
	byRegion []dbgen.AnalyticsUsersByRegionRow,
	regs []dbgen.AnalyticsUserRegistrationsLast30DaysRow,
) domain.AnalyticsUsersSection {
	roles := make([]domain.AnalyticsLabelCount, len(byRole))
	for i, r := range byRole {
		roles[i] = domain.AnalyticsLabelCount{Label: r.Role, Count: r.Count}
	}
	statuses := make([]domain.AnalyticsLabelCount, len(byStatus))
	for i, r := range byStatus {
		statuses[i] = domain.AnalyticsLabelCount{Label: r.Status, Count: r.Count}
	}
	ages := make([]domain.AnalyticsLabelCount, len(byAge))
	for i, r := range byAge {
		ages[i] = domain.AnalyticsLabelCount{Label: r.AgeGroup, Count: r.Count}
	}
	knowledge := make([]domain.AnalyticsLabelCount, len(byKnowledge))
	for i, r := range byKnowledge {
		knowledge[i] = domain.AnalyticsLabelCount{Label: r.KnowledgeLevel, Count: r.Count}
	}
	regions := make([]domain.AnalyticsLabelCount, len(byRegion))
	for i, r := range byRegion {
		regions[i] = domain.AnalyticsLabelCount{Label: r.Region, Count: r.Count}
	}
	timePoints := make([]domain.AnalyticsTimePoint, len(regs))
	for i, r := range regs {
		timePoints[i] = domain.AnalyticsTimePoint{Date: toTime(r.Date), Count: r.Count}
	}
	return domain.AnalyticsUsersSection{
		TotalUsers:              summary.Total,
		NewToday:                summary.NewToday,
		NewWeek:                 summary.NewThisWeek,
		NewMonth:                summary.NewThisMonth,
		ByRole:                  roles,
		ByStatus:                statuses,
		ByAgeGroup:              ages,
		ByKnowledgeLevel:        knowledge,
		ByRegion:                regions,
		RegistrationsLast30Days: timePoints,
	}
}

func mapSubscriptionsSection(
	summary dbgen.AnalyticsSubscriptionsSummaryRow,
	byStatus []dbgen.AnalyticsSubscriptionsByStatusRow,
	byPlan []dbgen.AnalyticsRevenueByPlanRow,
	newSubs []dbgen.AnalyticsNewSubscriptionsLast30DaysRow,
) domain.AnalyticsSubscriptionsSection {
	statuses := make([]domain.AnalyticsLabelCount, len(byStatus))
	for i, r := range byStatus {
		statuses[i] = domain.AnalyticsLabelCount{Label: r.Status, Count: r.Count}
	}
	plans := make([]domain.AnalyticsRevenueByPlan, len(byPlan))
	for i, r := range byPlan {
		plans[i] = domain.AnalyticsRevenueByPlan{PlanName: r.PlanName, Currency: r.Currency, Revenue: r.TotalRevenue}
	}
	timePoints := make([]domain.AnalyticsTimePoint, len(newSubs))
	for i, r := range newSubs {
		timePoints[i] = domain.AnalyticsTimePoint{Date: toTime(r.Date), Count: r.Count}
	}
	return domain.AnalyticsSubscriptionsSection{
		TotalSubscriptions:         summary.Total,
		ActiveSubscriptions:        summary.Active,
		NewToday:                   summary.NewToday,
		NewWeek:                    summary.NewThisWeek,
		NewMonth:                   summary.NewThisMonth,
		ByStatus:                   statuses,
		RevenueByPlan:              plans,
		NewSubscriptionsLast30Days: timePoints,
	}
}

func mapPaymentsSection(
	summary dbgen.AnalyticsPaymentsSummaryRow,
	byStatus []dbgen.AnalyticsPaymentsByStatusRow,
	byMethod []dbgen.AnalyticsPaymentsByMethodRow,
	revenue []dbgen.AnalyticsRevenueLast30DaysRow,
) domain.AnalyticsPaymentsSection {
	statuses := make([]domain.AnalyticsLabelAmount, len(byStatus))
	for i, r := range byStatus {
		statuses[i] = domain.AnalyticsLabelAmount{Label: r.Status, Count: r.Count, Amount: r.TotalAmount}
	}
	methods := make([]domain.AnalyticsLabelAmount, len(byMethod))
	for i, r := range byMethod {
		methods[i] = domain.AnalyticsLabelAmount{Label: r.PaymentMethod, Count: r.Count, Amount: r.TotalAmount}
	}
	timePoints := make([]domain.AnalyticsRevenueTimePoint, len(revenue))
	for i, r := range revenue {
		timePoints[i] = domain.AnalyticsRevenueTimePoint{Date: toTime(r.Date), Revenue: r.TotalRevenue}
	}
	return domain.AnalyticsPaymentsSection{
		TotalRevenue:        summary.TotalRevenue,
		AvgTransactionValue: summary.AvgValue,
		TotalPayments:       summary.TotalPayments,
		SuccessfulPayments:  summary.SuccessfulPayments,
		ByStatus:            statuses,
		ByMethod:            methods,
		RevenueLast30Days:   timePoints,
	}
}

func mapContentSection(
	counts dbgen.AnalyticsQuestionsCountsRow,
	byType []dbgen.AnalyticsQuestionsByTypeRow,
	setsByType []dbgen.AnalyticsQuestionSetsByTypeRow,
) domain.AnalyticsContentSection {
	qTypes := make([]domain.AnalyticsLabelCount, len(byType))
	for i, r := range byType {
		qTypes[i] = domain.AnalyticsLabelCount{Label: r.QuestionType, Count: r.Count}
	}
	sTypes := make([]domain.AnalyticsLabelCount, len(setsByType))
	for i, r := range setsByType {
		sTypes[i] = domain.AnalyticsLabelCount{Label: r.SetType, Count: r.Count}
	}
	return domain.AnalyticsContentSection{
		TotalQuestions:     counts.TotalQuestions,
		TotalQuestionSets:  counts.TotalQuestionSets,
		QuestionsByType:    qTypes,
		QuestionSetsByType: sTypes,
	}
}

func mapNotificationsSection(
	summary dbgen.AnalyticsNotificationsSummaryRow,
	byChannel []dbgen.AnalyticsNotificationsByChannelRow,
	byType []dbgen.AnalyticsNotificationsByTypeRow,
) domain.AnalyticsNotificationsSection {
	channels := make([]domain.AnalyticsLabelCount, len(byChannel))
	for i, r := range byChannel {
		channels[i] = domain.AnalyticsLabelCount{Label: r.Channel, Count: r.Count}
	}
	types := make([]domain.AnalyticsLabelCount, len(byType))
	for i, r := range byType {
		types[i] = domain.AnalyticsLabelCount{Label: r.Type, Count: r.Count}
	}
	return domain.AnalyticsNotificationsSection{
		TotalSent:   summary.Total,
		ReadCount:   summary.Read,
		UnreadCount: summary.Unread,
		ByChannel:   channels,
		ByType:      types,
	}
}

func mapIssuesSection(
	summary dbgen.AnalyticsIssuesSummaryRow,
	byStatus []dbgen.AnalyticsIssuesByStatusRow,
	byType []dbgen.AnalyticsIssuesByTypeRow,
) domain.AnalyticsIssuesSection {
	statuses := make([]domain.AnalyticsLabelCount, len(byStatus))
	for i, r := range byStatus {
		statuses[i] = domain.AnalyticsLabelCount{Label: r.Status, Count: r.Count}
	}
	types := make([]domain.AnalyticsLabelCount, len(byType))
	for i, r := range byType {
		types[i] = domain.AnalyticsLabelCount{Label: r.IssueType, Count: r.Count}
	}
	return domain.AnalyticsIssuesSection{
		TotalIssues:    summary.Total,
		ResolvedIssues: summary.Resolved,
		ResolutionRate: summary.ResolutionRate,
		ByStatus:       statuses,
		ByType:         types,
	}
}

func mapTeamSection(
	totalMembers int64,
	byRole []dbgen.AnalyticsTeamByRoleRow,
	byStatus []dbgen.AnalyticsTeamByStatusRow,
) domain.AnalyticsTeamSection {
	roles := make([]domain.AnalyticsLabelCount, len(byRole))
	for i, r := range byRole {
		roles[i] = domain.AnalyticsLabelCount{Label: r.TeamRole, Count: r.Count}
	}
	statuses := make([]domain.AnalyticsLabelCount, len(byStatus))
	for i, r := range byStatus {
		statuses[i] = domain.AnalyticsLabelCount{Label: r.Status, Count: r.Count}
	}
	return domain.AnalyticsTeamSection{
		TotalMembers: totalMembers,
		ByRole:       roles,
		ByStatus:     statuses,
	}
}
