package io.synor.economics;

import java.util.List;

/**
 * Economics SDK Types for Java.
 */
public class Types {
    // Organizational class
}

// ==================== Enums ====================

enum ServiceType { compute, storage, database, hosting, bridge, mining, rpc }
enum BillingPeriod { daily, weekly, monthly, yearly }
enum StakeStatus { active, unstaking, unlocked, slashed }
enum DiscountType { percentage, fixed, volume }

// ==================== Config ====================

class EconomicsConfig {
    private final String apiKey;
    private final String endpoint;
    private final int timeoutSecs;
    private final int retries;
    private final boolean debug;

    public EconomicsConfig(String apiKey) {
        this(apiKey, "https://economics.synor.io/v1", 60, 3, false);
    }

    public EconomicsConfig(String apiKey, String endpoint, int timeoutSecs, int retries, boolean debug) {
        this.apiKey = apiKey;
        this.endpoint = endpoint;
        this.timeoutSecs = timeoutSecs;
        this.retries = retries;
        this.debug = debug;
    }

    public String getApiKey() { return apiKey; }
    public String getEndpoint() { return endpoint; }
    public int getTimeoutSecs() { return timeoutSecs; }
    public int getRetries() { return retries; }
    public boolean isDebug() { return debug; }
}

// ==================== Pricing Types ====================

class UsageMetrics {
    private double computeHours;
    private double storageGb;
    private long requests;
    private double bandwidthGb;
    private double gpuHours;

    public double getComputeHours() { return computeHours; }
    public double getStorageGb() { return storageGb; }
    public long getRequests() { return requests; }
    public double getBandwidthGb() { return bandwidthGb; }
    public double getGpuHours() { return gpuHours; }

    public void setComputeHours(double computeHours) { this.computeHours = computeHours; }
    public void setStorageGb(double storageGb) { this.storageGb = storageGb; }
    public void setRequests(long requests) { this.requests = requests; }
    public void setBandwidthGb(double bandwidthGb) { this.bandwidthGb = bandwidthGb; }
    public void setGpuHours(double gpuHours) { this.gpuHours = gpuHours; }
}

class PricingTier {
    private String name;
    private double upTo;
    private double pricePerUnit;
    private String unit;

    public String getName() { return name; }
    public double getUpTo() { return upTo; }
    public double getPricePerUnit() { return pricePerUnit; }
    public String getUnit() { return unit; }
}

class Price {
    private ServiceType service;
    private String amount;
    private String currency;
    private String amountUsd;
    private List<PricingTier> breakdown;
    private String discount;
    private String finalAmount;

    public ServiceType getService() { return service; }
    public String getAmount() { return amount; }
    public String getCurrency() { return currency; }
    public String getAmountUsd() { return amountUsd; }
    public List<PricingTier> getBreakdown() { return breakdown; }
    public String getDiscount() { return discount; }
    public String getFinalAmount() { return finalAmount; }
}

class UsagePlan {
    private ServiceType service;
    private UsageMetrics estimatedUsage;
    private BillingPeriod period;

    public ServiceType getService() { return service; }
    public UsageMetrics getEstimatedUsage() { return estimatedUsage; }
    public BillingPeriod getPeriod() { return period; }

    public void setService(ServiceType service) { this.service = service; }
    public void setEstimatedUsage(UsageMetrics estimatedUsage) { this.estimatedUsage = estimatedUsage; }
    public void setPeriod(BillingPeriod period) { this.period = period; }
}

class CostEstimate {
    private ServiceType service;
    private BillingPeriod period;
    private String estimatedCost;
    private String estimatedCostUsd;
    private String currency;
    private String confidenceLevel;
    private List<CostBreakdown> breakdown;
    private String savingsFromStaking;

    public ServiceType getService() { return service; }
    public BillingPeriod getPeriod() { return period; }
    public String getEstimatedCost() { return estimatedCost; }
    public String getEstimatedCostUsd() { return estimatedCostUsd; }
    public String getCurrency() { return currency; }
    public String getConfidenceLevel() { return confidenceLevel; }
    public List<CostBreakdown> getBreakdown() { return breakdown; }
    public String getSavingsFromStaking() { return savingsFromStaking; }
}

class CostBreakdown {
    private String category;
    private String amount;
    private double percentage;

    public String getCategory() { return category; }
    public String getAmount() { return amount; }
    public double getPercentage() { return percentage; }
}

// ==================== Billing Types ====================

class UsageRecord {
    private ServiceType service;
    private String resource;
    private double quantity;
    private String unit;
    private long timestamp;
    private String cost;

    public ServiceType getService() { return service; }
    public String getResource() { return resource; }
    public double getQuantity() { return quantity; }
    public String getUnit() { return unit; }
    public long getTimestamp() { return timestamp; }
    public String getCost() { return cost; }
}

class Usage {
    private BillingPeriod period;
    private long startDate;
    private long endDate;
    private List<UsageRecord> records;
    private String totalCost;
    private String currency;

    public BillingPeriod getPeriod() { return period; }
    public long getStartDate() { return startDate; }
    public long getEndDate() { return endDate; }
    public List<UsageRecord> getRecords() { return records; }
    public String getTotalCost() { return totalCost; }
    public String getCurrency() { return currency; }
}

class InvoiceLineItem {
    private String description;
    private double quantity;
    private String unit;
    private String unitPrice;
    private String amount;

    public String getDescription() { return description; }
    public double getQuantity() { return quantity; }
    public String getUnit() { return unit; }
    public String getUnitPrice() { return unitPrice; }
    public String getAmount() { return amount; }
}

class Invoice {
    private String id;
    private String number;
    private long periodStart;
    private long periodEnd;
    private String subtotal;
    private String tax;
    private String discount;
    private String total;
    private String currency;
    private String status;
    private Long dueDate;
    private Long paidAt;
    private List<InvoiceLineItem> lineItems;
    private String pdfUrl;

    public String getId() { return id; }
    public String getNumber() { return number; }
    public long getPeriodStart() { return periodStart; }
    public long getPeriodEnd() { return periodEnd; }
    public String getSubtotal() { return subtotal; }
    public String getTax() { return tax; }
    public String getDiscount() { return discount; }
    public String getTotal() { return total; }
    public String getCurrency() { return currency; }
    public String getStatus() { return status; }
    public Long getDueDate() { return dueDate; }
    public Long getPaidAt() { return paidAt; }
    public List<InvoiceLineItem> getLineItems() { return lineItems; }
    public String getPdfUrl() { return pdfUrl; }
}

class AccountBalance {
    private String available;
    private String pending;
    private String reserved;
    private String staked;
    private String currency;
    private long lastUpdated;

    public String getAvailable() { return available; }
    public String getPending() { return pending; }
    public String getReserved() { return reserved; }
    public String getStaked() { return staked; }
    public String getCurrency() { return currency; }
    public long getLastUpdated() { return lastUpdated; }
}

// ==================== Staking Types ====================

class StakeReceipt {
    private String id;
    private String txHash;
    private String amount;
    private long startDate;
    private long endDate;
    private double apy;
    private StakeStatus status;

    public String getId() { return id; }
    public String getTxHash() { return txHash; }
    public String getAmount() { return amount; }
    public long getStartDate() { return startDate; }
    public long getEndDate() { return endDate; }
    public double getApy() { return apy; }
    public StakeStatus getStatus() { return status; }
}

class StakeInfo {
    private String id;
    private String amount;
    private StakeStatus status;
    private long startDate;
    private long endDate;
    private double apy;
    private String earnedRewards;
    private String pendingRewards;
    private Long unlockDate;
    private int discountPercent;

    public String getId() { return id; }
    public String getAmount() { return amount; }
    public StakeStatus getStatus() { return status; }
    public long getStartDate() { return startDate; }
    public long getEndDate() { return endDate; }
    public double getApy() { return apy; }
    public String getEarnedRewards() { return earnedRewards; }
    public String getPendingRewards() { return pendingRewards; }
    public Long getUnlockDate() { return unlockDate; }
    public int getDiscountPercent() { return discountPercent; }
}

class UnstakeReceipt {
    private String id;
    private String txHash;
    private String amount;
    private long initiatedAt;
    private long availableAt;
    private String penalty;

    public String getId() { return id; }
    public String getTxHash() { return txHash; }
    public String getAmount() { return amount; }
    public long getInitiatedAt() { return initiatedAt; }
    public long getAvailableAt() { return availableAt; }
    public String getPenalty() { return penalty; }
}

class Rewards {
    private String totalEarned;
    private String pendingClaim;
    private String lastClaimDate;
    private double currentApy;
    private List<RewardRecord> history;

    public String getTotalEarned() { return totalEarned; }
    public String getPendingClaim() { return pendingClaim; }
    public String getLastClaimDate() { return lastClaimDate; }
    public double getCurrentApy() { return currentApy; }
    public List<RewardRecord> getHistory() { return history; }
}

class RewardRecord {
    private long date;
    private String amount;
    private String type;
    private String txHash;

    public long getDate() { return date; }
    public String getAmount() { return amount; }
    public String getType() { return type; }
    public String getTxHash() { return txHash; }
}

// ==================== Discount Types ====================

class Discount {
    private String id;
    private String code;
    private DiscountType type;
    private String value;
    private Long validFrom;
    private Long validUntil;
    private Integer usageLimit;
    private int usageCount;
    private List<ServiceType> applicableServices;
    private String minimumSpend;
    private boolean active;

    public String getId() { return id; }
    public String getCode() { return code; }
    public DiscountType getType() { return type; }
    public String getValue() { return value; }
    public Long getValidFrom() { return validFrom; }
    public Long getValidUntil() { return validUntil; }
    public Integer getUsageLimit() { return usageLimit; }
    public int getUsageCount() { return usageCount; }
    public List<ServiceType> getApplicableServices() { return applicableServices; }
    public String getMinimumSpend() { return minimumSpend; }
    public boolean isActive() { return active; }
}

class AppliedDiscount {
    private Discount discount;
    private String savedAmount;
    private long appliedAt;

    public Discount getDiscount() { return discount; }
    public String getSavedAmount() { return savedAmount; }
    public long getAppliedAt() { return appliedAt; }
}

// ==================== Error ====================

class EconomicsException extends RuntimeException {
    private final String code;
    private final int statusCode;

    public EconomicsException(String message) {
        super(message);
        this.code = null;
        this.statusCode = 0;
    }

    public EconomicsException(String message, String code, int statusCode) {
        super(message);
        this.code = code;
        this.statusCode = statusCode;
    }

    public String getCode() { return code; }
    public int getStatusCode() { return statusCode; }
}
