package io.synor.mining;

import java.util.List;

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

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

enum DeviceType { cpu, gpu_nvidia, gpu_amd, asic }
enum DeviceStatus { idle, mining, error, offline }
enum ConnectionStatus { disconnected, connecting, connected, reconnecting }
enum TimePeriod { hour, day, week, month, all }
enum SubmitResultStatus { accepted, rejected, stale }

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

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

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

    public MiningConfig(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; }
}

// ==================== Pool Types ====================

class PoolConfig {
    private String url;
    private String user;
    private String password;
    private String algorithm;
    private Double difficulty;

    public String getUrl() { return url; }
    public String getUser() { return user; }
    public String getPassword() { return password; }
    public String getAlgorithm() { return algorithm; }
    public Double getDifficulty() { return difficulty; }

    public void setUrl(String url) { this.url = url; }
    public void setUser(String user) { this.user = user; }
    public void setPassword(String password) { this.password = password; }
    public void setAlgorithm(String algorithm) { this.algorithm = algorithm; }
    public void setDifficulty(Double difficulty) { this.difficulty = difficulty; }
}

class StratumConnection {
    private String id;
    private String pool;
    private ConnectionStatus status;
    private String algorithm;
    private double difficulty;
    private long connectedAt;
    private int acceptedShares;
    private int rejectedShares;
    private int staleShares;
    private Long lastShareAt;

    public String getId() { return id; }
    public String getPool() { return pool; }
    public ConnectionStatus getStatus() { return status; }
    public String getAlgorithm() { return algorithm; }
    public double getDifficulty() { return difficulty; }
    public long getConnectedAt() { return connectedAt; }
    public int getAcceptedShares() { return acceptedShares; }
    public int getRejectedShares() { return rejectedShares; }
    public int getStaleShares() { return staleShares; }
    public Long getLastShareAt() { return lastShareAt; }
}

class PoolStats {
    private String url;
    private int workers;
    private double hashrate;
    private double difficulty;
    private long lastBlock;
    private int blocksFound24h;
    private double luck;

    public String getUrl() { return url; }
    public int getWorkers() { return workers; }
    public double getHashrate() { return hashrate; }
    public double getDifficulty() { return difficulty; }
    public long getLastBlock() { return lastBlock; }
    public int getBlocksFound24h() { return blocksFound24h; }
    public double getLuck() { return luck; }
}

// ==================== Mining Types ====================

class TemplateTransaction {
    private String txid;
    private String data;
    private String fee;
    private int weight;

    public String getTxid() { return txid; }
    public String getData() { return data; }
    public String getFee() { return fee; }
    public int getWeight() { return weight; }
}

class BlockTemplate {
    private String id;
    private String previousBlockHash;
    private String merkleRoot;
    private long timestamp;
    private String bits;
    private long height;
    private String coinbaseValue;
    private List<TemplateTransaction> transactions;
    private String target;
    private String algorithm;
    private String extraNonce;

    public String getId() { return id; }
    public String getPreviousBlockHash() { return previousBlockHash; }
    public String getMerkleRoot() { return merkleRoot; }
    public long getTimestamp() { return timestamp; }
    public String getBits() { return bits; }
    public long getHeight() { return height; }
    public String getCoinbaseValue() { return coinbaseValue; }
    public List<TemplateTransaction> getTransactions() { return transactions; }
    public String getTarget() { return target; }
    public String getAlgorithm() { return algorithm; }
    public String getExtraNonce() { return extraNonce; }
}

class MinedWork {
    private String templateId;
    private String nonce;
    private String extraNonce;
    private long timestamp;
    private String hash;

    public String getTemplateId() { return templateId; }
    public String getNonce() { return nonce; }
    public String getExtraNonce() { return extraNonce; }
    public long getTimestamp() { return timestamp; }
    public String getHash() { return hash; }

    public void setTemplateId(String templateId) { this.templateId = templateId; }
    public void setNonce(String nonce) { this.nonce = nonce; }
    public void setExtraNonce(String extraNonce) { this.extraNonce = extraNonce; }
    public void setTimestamp(long timestamp) { this.timestamp = timestamp; }
    public void setHash(String hash) { this.hash = hash; }
}

class ShareInfo {
    private String hash;
    private double difficulty;
    private long timestamp;
    private boolean accepted;

    public String getHash() { return hash; }
    public double getDifficulty() { return difficulty; }
    public long getTimestamp() { return timestamp; }
    public boolean isAccepted() { return accepted; }
}

class SubmitResult {
    private SubmitResultStatus status;
    private ShareInfo share;
    private boolean blockFound;
    private String reason;
    private String blockHash;
    private String reward;

    public SubmitResultStatus getStatus() { return status; }
    public ShareInfo getShare() { return share; }
    public boolean isBlockFound() { return blockFound; }
    public String getReason() { return reason; }
    public String getBlockHash() { return blockHash; }
    public String getReward() { return reward; }
}

// ==================== Stats Types ====================

class Hashrate {
    private double current;
    private double average1h;
    private double average24h;
    private double peak;
    private String unit;

    public double getCurrent() { return current; }
    public double getAverage1h() { return average1h; }
    public double getAverage24h() { return average24h; }
    public double getPeak() { return peak; }
    public String getUnit() { return unit; }
}

class ShareStats {
    private int accepted;
    private int rejected;
    private int stale;
    private int total;
    private double acceptRate;

    public int getAccepted() { return accepted; }
    public int getRejected() { return rejected; }
    public int getStale() { return stale; }
    public int getTotal() { return total; }
    public double getAcceptRate() { return acceptRate; }
}

class DeviceTemperature {
    private double current;
    private double max;
    private boolean throttling;

    public double getCurrent() { return current; }
    public double getMax() { return max; }
    public boolean isThrottling() { return throttling; }
}

class EarningsSnapshot {
    private String today;
    private String yesterday;
    private String thisWeek;
    private String thisMonth;
    private String total;
    private String currency;

    public String getToday() { return today; }
    public String getYesterday() { return yesterday; }
    public String getThisWeek() { return thisWeek; }
    public String getThisMonth() { return thisMonth; }
    public String getTotal() { return total; }
    public String getCurrency() { return currency; }
}

class MiningStats {
    private Hashrate hashrate;
    private ShareStats shares;
    private long uptime;
    private double efficiency;
    private EarningsSnapshot earnings;
    private Double powerConsumption;
    private DeviceTemperature temperature;

    public Hashrate getHashrate() { return hashrate; }
    public ShareStats getShares() { return shares; }
    public long getUptime() { return uptime; }
    public double getEfficiency() { return efficiency; }
    public EarningsSnapshot getEarnings() { return earnings; }
    public Double getPowerConsumption() { return powerConsumption; }
    public DeviceTemperature getTemperature() { return temperature; }
}

class EarningsBreakdown {
    private long date;
    private String amount;
    private int blocks;
    private int shares;
    private double hashrate;

    public long getDate() { return date; }
    public String getAmount() { return amount; }
    public int getBlocks() { return blocks; }
    public int getShares() { return shares; }
    public double getHashrate() { return hashrate; }
}

class Earnings {
    private TimePeriod period;
    private long startDate;
    private long endDate;
    private String amount;
    private int blocks;
    private int shares;
    private double averageHashrate;
    private String currency;
    private List<EarningsBreakdown> breakdown;

    public TimePeriod getPeriod() { return period; }
    public long getStartDate() { return startDate; }
    public long getEndDate() { return endDate; }
    public String getAmount() { return amount; }
    public int getBlocks() { return blocks; }
    public int getShares() { return shares; }
    public double getAverageHashrate() { return averageHashrate; }
    public String getCurrency() { return currency; }
    public List<EarningsBreakdown> getBreakdown() { return breakdown; }
}

// ==================== Device Types ====================

class MiningDevice {
    private String id;
    private String name;
    private DeviceType type;
    private DeviceStatus status;
    private double hashrate;
    private double temperature;
    private double fanSpeed;
    private double powerDraw;
    private long memoryUsed;
    private long memoryTotal;
    private String driver;
    private String firmware;

    public String getId() { return id; }
    public String getName() { return name; }
    public DeviceType getType() { return type; }
    public DeviceStatus getStatus() { return status; }
    public double getHashrate() { return hashrate; }
    public double getTemperature() { return temperature; }
    public double getFanSpeed() { return fanSpeed; }
    public double getPowerDraw() { return powerDraw; }
    public long getMemoryUsed() { return memoryUsed; }
    public long getMemoryTotal() { return memoryTotal; }
    public String getDriver() { return driver; }
    public String getFirmware() { return firmware; }
}

class DeviceConfig {
    private boolean enabled;
    private Integer intensity;
    private Integer powerLimit;
    private Integer coreClockOffset;
    private Integer memoryClockOffset;
    private Integer fanSpeed;

    public boolean isEnabled() { return enabled; }
    public Integer getIntensity() { return intensity; }
    public Integer getPowerLimit() { return powerLimit; }
    public Integer getCoreClockOffset() { return coreClockOffset; }
    public Integer getMemoryClockOffset() { return memoryClockOffset; }
    public Integer getFanSpeed() { return fanSpeed; }

    public void setEnabled(boolean enabled) { this.enabled = enabled; }
    public void setIntensity(Integer intensity) { this.intensity = intensity; }
    public void setPowerLimit(Integer powerLimit) { this.powerLimit = powerLimit; }
    public void setCoreClockOffset(Integer coreClockOffset) { this.coreClockOffset = coreClockOffset; }
    public void setMemoryClockOffset(Integer memoryClockOffset) { this.memoryClockOffset = memoryClockOffset; }
    public void setFanSpeed(Integer fanSpeed) { this.fanSpeed = fanSpeed; }
}

// ==================== Worker Types ====================

class WorkerInfo {
    private String id;
    private String name;
    private ConnectionStatus status;
    private Hashrate hashrate;
    private ShareStats shares;
    private List<MiningDevice> devices;
    private long lastSeen;
    private long uptime;

    public String getId() { return id; }
    public String getName() { return name; }
    public ConnectionStatus getStatus() { return status; }
    public Hashrate getHashrate() { return hashrate; }
    public ShareStats getShares() { return shares; }
    public List<MiningDevice> getDevices() { return devices; }
    public long getLastSeen() { return lastSeen; }
    public long getUptime() { return uptime; }
}

// ==================== Algorithm Types ====================

class MiningAlgorithm {
    private String name;
    private String displayName;
    private String hashUnit;
    private String profitability;
    private double difficulty;
    private String blockReward;
    private int blockTime;

    public String getName() { return name; }
    public String getDisplayName() { return displayName; }
    public String getHashUnit() { return hashUnit; }
    public String getProfitability() { return profitability; }
    public double getDifficulty() { return difficulty; }
    public String getBlockReward() { return blockReward; }
    public int getBlockTime() { return blockTime; }
}

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

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

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

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

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