import { Equal, Hash, HashSet, Inspectable, Schema } from "effect";
import * as Address from "./Address.js";
import * as Assets from "./Assets.js";
import * as DatumOption from "./DatumOption.js";
import * as Numeric from "./Numeric.js";
import * as Script from "./Script.js";
import * as TransactionHash from "./TransactionHash.js";
import * as TransactionInput from "./TransactionInput.js";
/**
 * UTxO (Unspent Transaction Output) - A transaction output with its on-chain reference.
 *
 * Combines TransactionOutput with the transaction reference (transactionId + index)
 * that uniquely identifies it on the blockchain.
 *
 * @since 2.0.0
 * @category model
 */
export class UTxO extends /*#__PURE__*/Schema.TaggedClass()("UTxO", {
  transactionId: TransactionHash.TransactionHash,
  index: Numeric.Uint16Schema,
  address: Address.Address,
  assets: /*#__PURE__*/Assets.Assets.pipe(/*#__PURE__*/Schema.filter(Assets.allPositive, {
    message: () => "UTxO assets must have non-negative lovelace and positive token quantities"
  })),
  datumOption: /*#__PURE__*/Schema.optional(DatumOption.DatumOptionSchema),
  scriptRef: /*#__PURE__*/Schema.optional(Script.Script)
}) {
  toJSON() {
    // Serialize Script to hex representation
    const scriptRefJson = this.scriptRef ? {
      _tag: this.scriptRef._tag,
      cbor: Script.toCBORHex(this.scriptRef)
    } : undefined;
    return {
      _tag: this._tag,
      transactionId: this.transactionId.toJSON(),
      index: this.index.toString(),
      address: this.address.toJSON(),
      assets: this.assets.toJSON(),
      datumOption: this.datumOption?.toJSON(),
      scriptRef: scriptRefJson
    };
  }
  toString() {
    return Inspectable.format(this.toJSON());
  }
  [Equal.symbol](that) {
    return that instanceof UTxO && Equal.equals(this.transactionId, that.transactionId) && this.index === that.index && Equal.equals(this.address, that.address) && Equal.equals(this.assets, that.assets) && Equal.equals(this.datumOption, that.datumOption) && Equal.equals(this.scriptRef, that.scriptRef);
  }
  [Hash.symbol]() {
    return Hash.cached(this, Hash.combine(Hash.hash(this.transactionId))(Hash.number(Number(this.index))));
  }
}
/**
 * Check if the given value is a valid UTxO.
 *
 * @since 2.0.0
 * @category predicates
 */
export const isUTxO = /*#__PURE__*/Schema.is(UTxO);
/**
 * Create an empty UTxO set.
 *
 * @since 2.0.0
 * @category constructors
 */
export const empty = () => HashSet.empty();
/**
 * Create a UTxO set from an iterable of UTxOs.
 *
 * @since 2.0.0
 * @category constructors
 */
export const fromIterable = utxos => HashSet.fromIterable(utxos);
/**
 * Add a UTxO to the set.
 *
 * @since 2.0.0
 * @category combinators
 */
export const add = (set, utxo) => HashSet.add(set, utxo);
/**
 * Remove a UTxO from the set.
 *
 * @since 2.0.0
 * @category combinators
 */
export const remove = (set, utxo) => HashSet.remove(set, utxo);
/**
 * Check if a UTxO exists in the set.
 *
 * @since 2.0.0
 * @category predicates
 */
export const has = (set, utxo) => HashSet.has(set, utxo);
/**
 * Union of two UTxO sets.
 *
 * @since 2.0.0
 * @category combinators
 */
export const union = (a, b) => HashSet.union(a, b);
/**
 * Intersection of two UTxO sets.
 *
 * @since 2.0.0
 * @category combinators
 */
export const intersection = (a, b) => HashSet.intersection(a, b);
/**
 * Difference of two UTxO sets (elements in a but not in b).
 *
 * @since 2.0.0
 * @category combinators
 */
export const difference = (a, b) => HashSet.difference(a, b);
/**
 * Filter UTxOs in the set by predicate.
 *
 * @since 2.0.0
 * @category combinators
 */
export const filter = (set, predicate) => HashSet.filter(set, predicate);
/**
 * Get the number of UTxOs in the set.
 *
 * @since 2.0.0
 * @category getters
 */
export const size = set => HashSet.size(set);
/**
 * Check if the set is empty.
 *
 * @since 2.0.0
 * @category predicates
 */
export const isEmpty = set => HashSet.size(set) === 0;
/**
 * Convert a UTxO set to an array.
 *
 * @since 2.0.0
 * @category conversions
 */
export const toArray = set => Array.from(set);
/**
 * Get the output reference string for a UTxO (txHash#index format).
 *
 * @since 2.0.0
 * @category getters
 */
export const toOutRefString = utxo => `${TransactionHash.toHex(utxo.transactionId)}#${utxo.index}`;
// =============================================================================
// Aggregate Utilities
// =============================================================================
/**
 * Calculate total assets from a collection of UTxOs.
 *
 * @since 2.0.0
 * @category getters
 */
export const totalAssets = utxos => {
  const utxoArray = globalThis.Array.isArray(utxos) ? utxos : globalThis.Array.from(utxos);
  return utxoArray.reduce((total, utxo) => Assets.merge(total, utxo.assets), Assets.zero);
};
/**
 * Convert UTxOs to sorted TransactionInputs.
 * Inputs are sorted by transaction hash then output index for deterministic ordering.
 *
 * @since 2.0.0
 * @category conversions
 */
export const toInputs = utxos => {
  const inputs = utxos.map(utxo => new TransactionInput.TransactionInput({
    transactionId: utxo.transactionId,
    index: utxo.index
  }));
  // Sort inputs for deterministic ordering:
  // First by transaction hash, then by output index
  inputs.sort((a, b) => {
    const hashA = a.transactionId.hash;
    const hashB = b.transactionId.hash;
    for (let i = 0; i < hashA.length; i++) {
      if (hashA[i] !== hashB[i]) {
        return hashA[i] - hashB[i];
      }
    }
    return Number(a.index - b.index);
  });
  return inputs;
};
//# sourceMappingURL=UTxO.js.map