package com.tiedup.remake.prison;

import java.util.HashMap;
import java.util.Map;
import java.util.UUID;
import javax.annotation.Nullable;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.nbt.ListTag;
import net.minecraft.nbt.Tag;
import net.minecraft.world.item.Item;
import net.minecraft.world.item.Items;
import net.minecraftforge.registries.ForgeRegistries;

/**
 * Ransom/debt tracking for a prisoner.
 *
 * Simplified from RansomData - focused on debt tracking for the labor system.
 * Uses emeralds as the standard currency (matches LaborTask value system).
 */
public class RansomRecord {

    // ==================== CORE DATA ====================

    /** Total debt amount (in emeralds) */
    private int totalDebt;

    /** Amount already paid */
    private int amountPaid;

    /** When the ransom was created (game time) */
    private long createdTime;

    /** Item type for payment (default: emeralds) */
    private Item paymentItem;

    // ==================== CONTRIBUTIONS ====================

    /** Tracking who paid what (playerUUID -> amount) */
    private final Map<UUID, Integer> contributions;

    // ==================== CONSTRUCTOR ====================

    public RansomRecord() {
        this.totalDebt = 0;
        this.amountPaid = 0;
        this.createdTime = 0;
        this.paymentItem = Items.EMERALD;
        this.contributions = new HashMap<>();
    }

    public RansomRecord(int totalDebt, long createdTime) {
        this.totalDebt = totalDebt;
        this.amountPaid = 0;
        this.createdTime = createdTime;
        this.paymentItem = Items.EMERALD;
        this.contributions = new HashMap<>();
    }

    public RansomRecord(int totalDebt, Item paymentItem, long createdTime) {
        this.totalDebt = totalDebt;
        this.amountPaid = 0;
        this.createdTime = createdTime;
        this.paymentItem = paymentItem;
        this.contributions = new HashMap<>();
    }

    // ==================== GETTERS ====================

    public int getTotalDebt() {
        return totalDebt;
    }

    public int getAmountPaid() {
        return amountPaid;
    }

    public int getRemainingDebt() {
        return Math.max(0, totalDebt - amountPaid);
    }

    public long getCreatedTime() {
        return createdTime;
    }

    public Item getPaymentItem() {
        return paymentItem;
    }

    public Map<UUID, Integer> getContributions() {
        return new HashMap<>(contributions);
    }

    // ==================== PAYMENT ====================

    /**
     * Add a payment toward the ransom.
     *
     * @param amount Amount to pay
     * @return true if ransom is now fully paid
     */
    public boolean addPayment(int amount) {
        return addPayment(amount, null);
    }

    /**
     * Add a payment toward the ransom with contributor tracking.
     *
     * @param amount Amount to pay
     * @param contributorId UUID of player who paid (null for labor earnings)
     * @return true if ransom is now fully paid
     */
    public boolean addPayment(int amount, @Nullable UUID contributorId) {
        if (amount <= 0) {
            return isPaid();
        }

        this.amountPaid += amount;

        if (contributorId != null) {
            contributions.merge(contributorId, amount, Integer::sum);
        }

        return isPaid();
    }

    /**
     * Increase the debt (used for punishments).
     * Can make effective debt go into negative paid amount.
     *
     * @param amount Amount to increase debt by
     */
    public void increaseDebt(int amount) {
        if (amount > 0) {
            this.totalDebt += amount;
        }
    }

    /**
     * Set the total debt directly.
     * Used when initializing ransom.
     */
    public void setTotalDebt(int totalDebt) {
        this.totalDebt = Math.max(0, totalDebt);
    }

    // ==================== QUERY ====================

    /**
     * Check if ransom is fully paid.
     */
    public boolean isPaid() {
        return amountPaid >= totalDebt;
    }

    /**
     * Get payment progress as percentage (0-100).
     */
    public int getProgressPercent() {
        if (totalDebt <= 0) return 100;
        return Math.min(100, (amountPaid * 100) / totalDebt);
    }

    /**
     * Get contribution from a specific player.
     */
    public int getContribution(UUID playerId) {
        return contributions.getOrDefault(playerId, 0);
    }

    /**
     * Check if this record is active (has unpaid debt).
     */
    public boolean isActive() {
        return totalDebt > 0 && !isPaid();
    }

    // ==================== SERIALIZATION ====================

    public CompoundTag save() {
        CompoundTag tag = new CompoundTag();

        tag.putInt("totalDebt", totalDebt);
        tag.putInt("amountPaid", amountPaid);
        tag.putLong("createdTime", createdTime);

        var itemKey = ForgeRegistries.ITEMS.getKey(paymentItem);
        if (itemKey != null) {
            tag.putString("paymentItem", itemKey.toString());
        }

        // Save contributions
        if (!contributions.isEmpty()) {
            ListTag contribList = new ListTag();
            for (Map.Entry<UUID, Integer> entry : contributions.entrySet()) {
                CompoundTag contribTag = new CompoundTag();
                contribTag.putUUID("playerId", entry.getKey());
                contribTag.putInt("amount", entry.getValue());
                contribList.add(contribTag);
            }
            tag.put("contributions", contribList);
        }

        return tag;
    }

    public static RansomRecord load(CompoundTag tag) {
        RansomRecord record = new RansomRecord();

        record.totalDebt = tag.getInt("totalDebt");
        record.amountPaid = tag.getInt("amountPaid");
        record.createdTime = tag.getLong("createdTime");

        if (tag.contains("paymentItem")) {
            String itemKeyStr = tag.getString("paymentItem");
            var itemKey = net.minecraft.resources.ResourceLocation.tryParse(
                itemKeyStr
            );
            if (itemKey != null) {
                Item item = ForgeRegistries.ITEMS.getValue(itemKey);
                if (item != null && item != Items.AIR) {
                    record.paymentItem = item;
                }
            }
        }

        // Load contributions
        if (tag.contains("contributions")) {
            ListTag contribList = tag.getList(
                "contributions",
                Tag.TAG_COMPOUND
            );
            for (int i = 0; i < contribList.size(); i++) {
                CompoundTag contribTag = contribList.getCompound(i);
                UUID playerId = contribTag.getUUID("playerId");
                int amount = contribTag.getInt("amount");
                record.contributions.put(playerId, amount);
            }
        }

        return record;
    }

    /**
     * Reset to default state.
     */
    public void reset() {
        this.totalDebt = 0;
        this.amountPaid = 0;
        this.createdTime = 0;
        this.paymentItem = Items.EMERALD;
        this.contributions.clear();
    }

    @Override
    public String toString() {
        return String.format(
            "RansomRecord{debt=%d, paid=%d, remaining=%d}",
            totalDebt,
            amountPaid,
            getRemainingDebt()
        );
    }
}
