import { option as O, function as F } from 'fp-ts';
import { TSchema, Data } from '@evolution-sdk/evolution';
import {
  ProposalContentSchema,
  TreasuryWithdrawalSchema,
} from '../gov/types-new';
import { DEFAULT_SCHEMA_OPTIONS } from '../../types/evolution-schema-options';

const ExecuteDatumSchema = TSchema.Struct({
  id: TSchema.Integer,
  content: ProposalContentSchema,
  passedTime: TSchema.Integer,
  votingEndTime: TSchema.Integer,
  protocolVersion: TSchema.Integer,
  /// Value proposed to be withdrawn from the treasury as part of the proposal.
  treasuryWithdrawal: TSchema.NullOr(TreasuryWithdrawalSchema),
});

export type ExecuteDatum = typeof ExecuteDatumSchema.Type;

export function serialiseExecuteDatum(d: ExecuteDatum): string {
  return Data.withSchema(ExecuteDatumSchema).toCBORHex(d);
}

export function parseExecuteDatum(datum: string): O.Option<ExecuteDatum> {
  try {
    return O.some(
      Data.withSchema(ExecuteDatumSchema, DEFAULT_SCHEMA_OPTIONS).fromCBORHex(
        datum,
      ),
    );
  } catch (_) {
    return O.none;
  }
}

export function parseExecuteDatumOrThrow(datum: string): ExecuteDatum {
  return F.pipe(
    parseExecuteDatum(datum),
    O.match(() => {
      throw new Error('Expected an Execute datum.');
    }, F.identity),
  );
}
