package transformer

import (
	"apskel-pos-be/internal/contract"
	"apskel-pos-be/internal/models"
	"apskel-pos-be/internal/util"
	"fmt"
	"time"
)

// PaymentMethodAnalyticsContractToModel converts contract request to model
func PaymentMethodAnalyticsContractToModel(req *contract.PaymentMethodAnalyticsRequest) *models.PaymentMethodAnalyticsRequest {
	var dateFrom, dateTo time.Time

	if fromTime, toTime, err := util.ParseDateRangeToJakartaTime(req.DateFrom, req.DateTo); err == nil {
		if fromTime != nil {
			dateFrom = *fromTime
		}
		if toTime != nil {
			dateTo = *toTime
		}
	}

	return &models.PaymentMethodAnalyticsRequest{
		OrganizationID: req.OrganizationID,
		OutletID:       req.OutletID,
		DateFrom:       dateFrom,
		DateTo:         dateTo,
		GroupBy:        req.GroupBy,
	}
}

// PaymentMethodAnalyticsModelToContract converts model response to contract
func PaymentMethodAnalyticsModelToContract(resp *models.PaymentMethodAnalyticsResponse) *contract.PaymentMethodAnalyticsResponse {
	if resp == nil {
		return nil
	}

	var data []contract.PaymentMethodAnalyticsData
	for _, item := range resp.Data {
		data = append(data, contract.PaymentMethodAnalyticsData{
			PaymentMethodID:   item.PaymentMethodID,
			PaymentMethodName: item.PaymentMethodName,
			PaymentMethodType: item.PaymentMethodType,
			TotalAmount:       item.TotalAmount,
			OrderCount:        item.OrderCount,
			PaymentCount:      item.PaymentCount,
			Percentage:        item.Percentage,
		})
	}

	return &contract.PaymentMethodAnalyticsResponse{
		OrganizationID: resp.OrganizationID,
		OutletID:       resp.OutletID,
		DateFrom:       resp.DateFrom,
		DateTo:         resp.DateTo,
		GroupBy:        resp.GroupBy,
		Summary: contract.PaymentMethodSummary{
			TotalAmount:       resp.Summary.TotalAmount,
			TotalOrders:       resp.Summary.TotalOrders,
			TotalPayments:     resp.Summary.TotalPayments,
			AverageOrderValue: resp.Summary.AverageOrderValue,
		},
		Data: data,
	}
}

func SalesAnalyticsContractToModel(req *contract.SalesAnalyticsRequest) *models.SalesAnalyticsRequest {
	var dateFrom, dateTo time.Time

	if fromTime, toTime, err := util.ParseDateRangeToJakartaTime(req.DateFrom, req.DateTo); err == nil {
		if fromTime != nil {
			dateFrom = *fromTime
		}
		if toTime != nil {
			dateTo = *toTime
		}
	}

	return &models.SalesAnalyticsRequest{
		OrganizationID: req.OrganizationID,
		OutletID:       req.OutletID,
		DateFrom:       dateFrom,
		DateTo:         dateTo,
		GroupBy:        req.GroupBy,
	}
}

// SalesAnalyticsModelToContract converts model response to contract
func SalesAnalyticsModelToContract(resp *models.SalesAnalyticsResponse) *contract.SalesAnalyticsResponse {
	if resp == nil {
		return nil
	}

	var data []contract.SalesAnalyticsData
	for _, item := range resp.Data {
		data = append(data, contract.SalesAnalyticsData{
			Date:     item.Date,
			Sales:    item.Sales,
			Orders:   item.Orders,
			Items:    item.Items,
			Tax:      item.Tax,
			Discount: item.Discount,
			NetSales: item.NetSales,
		})
	}

	return &contract.SalesAnalyticsResponse{
		OrganizationID: resp.OrganizationID,
		OutletID:       resp.OutletID,
		DateFrom:       resp.DateFrom,
		DateTo:         resp.DateTo,
		GroupBy:        resp.GroupBy,
		Summary: contract.SalesSummary{
			TotalSales:        resp.Summary.TotalSales,
			TotalOrders:       resp.Summary.TotalOrders,
			TotalItems:        resp.Summary.TotalItems,
			AverageOrderValue: resp.Summary.AverageOrderValue,
			TotalTax:          resp.Summary.TotalTax,
			TotalDiscount:     resp.Summary.TotalDiscount,
			NetSales:          resp.Summary.NetSales,
		},
		Data: data,
	}
}

// ProductAnalyticsContractToModel converts contract request to model
func ProductAnalyticsContractToModel(req *contract.ProductAnalyticsRequest) *models.ProductAnalyticsRequest {
	var dateFrom, dateTo time.Time

	if fromTime, toTime, err := util.ParseDateRangeToJakartaTime(req.DateFrom, req.DateTo); err == nil {
		if fromTime != nil {
			dateFrom = *fromTime
		}
		if toTime != nil {
			dateTo = *toTime
		}
	}

	return &models.ProductAnalyticsRequest{
		OrganizationID: req.OrganizationID,
		OutletID:       req.OutletID,
		DateFrom:       dateFrom,
		DateTo:         dateTo,
		Limit:          req.Limit,
	}
}

// ProductAnalyticsModelToContract converts model response to contract
func ProductAnalyticsModelToContract(resp *models.ProductAnalyticsResponse) *contract.ProductAnalyticsResponse {
	if resp == nil {
		return nil
	}

	var data []contract.ProductAnalyticsData
	for _, item := range resp.Data {
		data = append(data, contract.ProductAnalyticsData{
			ProductID:    item.ProductID,
			ProductName:  item.ProductName,
			CategoryID:   item.CategoryID,
			CategoryName: item.CategoryName,
			QuantitySold: item.QuantitySold,
			Revenue:      item.Revenue,
			AveragePrice: item.AveragePrice,
			OrderCount:   item.OrderCount,
		})
	}

	return &contract.ProductAnalyticsResponse{
		OrganizationID: resp.OrganizationID,
		OutletID:       resp.OutletID,
		DateFrom:       resp.DateFrom,
		DateTo:         resp.DateTo,
		Data:           data,
	}
}

// ProductAnalyticsPerCategoryContractToModel converts contract request to model
func ProductAnalyticsPerCategoryContractToModel(req *contract.ProductAnalyticsPerCategoryRequest) *models.ProductAnalyticsPerCategoryRequest {
	var dateFrom, dateTo time.Time

	// Parse date range using utility function
	if fromTime, toTime, err := util.ParseDateRangeToJakartaTime(req.DateFrom, req.DateTo); err == nil {
		if fromTime != nil {
			dateFrom = *fromTime
		}
		if toTime != nil {
			dateTo = *toTime
		}
	}

	return &models.ProductAnalyticsPerCategoryRequest{
		OrganizationID: req.OrganizationID,
		OutletID:       req.OutletID,
		DateFrom:       dateFrom,
		DateTo:         dateTo,
	}
}

// ProductAnalyticsPerCategoryModelToContract converts model response to contract
func ProductAnalyticsPerCategoryModelToContract(resp *models.ProductAnalyticsPerCategoryResponse) *contract.ProductAnalyticsPerCategoryResponse {
	if resp == nil {
		return nil
	}

	var data []contract.ProductAnalyticsPerCategoryData
	for _, item := range resp.Data {
		data = append(data, contract.ProductAnalyticsPerCategoryData{
			CategoryID:   item.CategoryID,
			CategoryName: item.CategoryName,
			TotalRevenue: item.TotalRevenue,
			TotalQuantity: item.TotalQuantity,
			ProductCount: item.ProductCount,
			OrderCount:   item.OrderCount,
		})
	}

	return &contract.ProductAnalyticsPerCategoryResponse{
		OrganizationID: resp.OrganizationID,
		OutletID:       resp.OutletID,
		DateFrom:       resp.DateFrom,
		DateTo:         resp.DateTo,
		Data:           data,
	}
}

// DashboardAnalyticsContractToModel converts contract request to model
func DashboardAnalyticsContractToModel(req *contract.DashboardAnalyticsRequest) *models.DashboardAnalyticsRequest {
	var dateFrom, dateTo time.Time

	// Parse date range using utility function
	if fromTime, toTime, err := util.ParseDateRangeToJakartaTime(req.DateFrom, req.DateTo); err == nil {
		if fromTime != nil {
			dateFrom = *fromTime
		}
		if toTime != nil {
			dateTo = *toTime
		}
	}

	return &models.DashboardAnalyticsRequest{
		OrganizationID: req.OrganizationID,
		OutletID:       req.OutletID,
		DateFrom:       dateFrom,
		DateTo:         dateTo,
	}
}

// DashboardAnalyticsModelToContract converts model response to contract
func DashboardAnalyticsModelToContract(resp *models.DashboardAnalyticsResponse) *contract.DashboardAnalyticsResponse {
	if resp == nil {
		return nil
	}

	var topProducts []contract.ProductAnalyticsData
	for _, item := range resp.TopProducts {
		topProducts = append(topProducts, contract.ProductAnalyticsData{
			ProductID:    item.ProductID,
			ProductName:  item.ProductName,
			CategoryID:   item.CategoryID,
			CategoryName: item.CategoryName,
			QuantitySold: item.QuantitySold,
			Revenue:      item.Revenue,
			AveragePrice: item.AveragePrice,
			OrderCount:   item.OrderCount,
		})
	}

	var paymentMethods []contract.PaymentMethodAnalyticsData
	for _, item := range resp.PaymentMethods {
		paymentMethods = append(paymentMethods, contract.PaymentMethodAnalyticsData{
			PaymentMethodID:   item.PaymentMethodID,
			PaymentMethodName: item.PaymentMethodName,
			PaymentMethodType: item.PaymentMethodType,
			TotalAmount:       item.TotalAmount,
			OrderCount:        item.OrderCount,
			PaymentCount:      item.PaymentCount,
			Percentage:        item.Percentage,
		})
	}

	var recentSales []contract.SalesAnalyticsData
	for _, item := range resp.RecentSales {
		recentSales = append(recentSales, contract.SalesAnalyticsData{
			Date:     item.Date,
			Sales:    item.Sales,
			Orders:   item.Orders,
			Items:    item.Items,
			Tax:      item.Tax,
			Discount: item.Discount,
			NetSales: item.NetSales,
		})
	}

	return &contract.DashboardAnalyticsResponse{
		OrganizationID: resp.OrganizationID,
		OutletID:       resp.OutletID,
		DateFrom:       resp.DateFrom,
		DateTo:         resp.DateTo,
		Overview: contract.DashboardOverview{
			TotalSales:        resp.Overview.TotalSales,
			TotalOrders:       resp.Overview.TotalOrders,
			AverageOrderValue: resp.Overview.AverageOrderValue,
			TotalCustomers:    resp.Overview.TotalCustomers,
			VoidedOrders:      resp.Overview.VoidedOrders,
			RefundedOrders:    resp.Overview.RefundedOrders,
		},
		TopProducts:    topProducts,
		PaymentMethods: paymentMethods,
		RecentSales:    recentSales,
	}
}

// ProfitLossAnalyticsContractToModel transforms contract request to model
func ProfitLossAnalyticsContractToModel(req *contract.ProfitLossAnalyticsRequest) (*models.ProfitLossAnalyticsRequest, error) {
	if req == nil {
		return nil, fmt.Errorf("request cannot be nil")
	}

	// Parse date range using utility function
	dateFrom, dateTo, err := util.ParseDateRangeToJakartaTime(req.DateFrom, req.DateTo)
	if err != nil {
		return nil, fmt.Errorf("invalid date format: %w", err)
	}

	if dateFrom == nil || dateTo == nil {
		return nil, fmt.Errorf("both date_from and date_to are required")
	}

	return &models.ProfitLossAnalyticsRequest{
		OrganizationID: req.OrganizationID,
		OutletID:       req.OutletID,
		DateFrom:       *dateFrom,
		DateTo:         *dateTo,
		GroupBy:        req.GroupBy,
	}, nil
}

// ProfitLossAnalyticsModelToContract transforms model response to contract
func ProfitLossAnalyticsModelToContract(resp *models.ProfitLossAnalyticsResponse) *contract.ProfitLossAnalyticsResponse {
	if resp == nil {
		return nil
	}

	// Transform profit/loss data
	data := make([]contract.ProfitLossData, len(resp.Data))
	for i, item := range resp.Data {
		data[i] = contract.ProfitLossData{
			Date:              item.Date,
			Revenue:           item.Revenue,
			Cost:              item.Cost,
			GrossProfit:       item.GrossProfit,
			GrossProfitMargin: item.GrossProfitMargin,
			Tax:               item.Tax,
			Discount:          item.Discount,
			NetProfit:         item.NetProfit,
			NetProfitMargin:   item.NetProfitMargin,
			Orders:            item.Orders,
		}
	}

	// Transform product profit data
	productData := make([]contract.ProductProfitData, len(resp.ProductData))
	for i, item := range resp.ProductData {
		productData[i] = contract.ProductProfitData{
			ProductID:         item.ProductID,
			ProductName:       item.ProductName,
			CategoryID:        item.CategoryID,
			CategoryName:      item.CategoryName,
			QuantitySold:      item.QuantitySold,
			Revenue:           item.Revenue,
			Cost:              item.Cost,
			GrossProfit:       item.GrossProfit,
			GrossProfitMargin: item.GrossProfitMargin,
			AveragePrice:      item.AveragePrice,
			AverageCost:       item.AverageCost,
			ProfitPerUnit:     item.ProfitPerUnit,
		}
	}

	return &contract.ProfitLossAnalyticsResponse{
		OrganizationID: resp.OrganizationID,
		OutletID:       resp.OutletID,
		DateFrom:       resp.DateFrom,
		DateTo:         resp.DateTo,
		GroupBy:        resp.GroupBy,
		Summary: contract.ProfitLossSummary{
			TotalRevenue:       resp.Summary.TotalRevenue,
			TotalCost:          resp.Summary.TotalCost,
			GrossProfit:        resp.Summary.GrossProfit,
			GrossProfitMargin:  resp.Summary.GrossProfitMargin,
			TotalTax:           resp.Summary.TotalTax,
			TotalDiscount:      resp.Summary.TotalDiscount,
			NetProfit:          resp.Summary.NetProfit,
			NetProfitMargin:    resp.Summary.NetProfitMargin,
			TotalOrders:        resp.Summary.TotalOrders,
			AverageProfit:      resp.Summary.AverageProfit,
			ProfitabilityRatio: resp.Summary.ProfitabilityRatio,
		},
		Data:        data,
		ProductData: productData,
	}
}
