import { z, g as createDocument, s as saveToFile, l as loadFromFile, r as readFile, J as JSZip, e as loadFromInput, f as createZip, j as hashAttachment, h as hashKey, c as createReducer, i as isBaseAction, a as createAction, B as BaseDocument, b as applyMixins, d as BaseActions } from './object-693686d0.js';
import 'json-stringify-deterministic';
import 'immer';
import 'crypto';
import 'fs';
import 'https';
import 'path';

// node_modules/@acaldas/document-model-graphql/dist/index-638f3b20.js
var y = (n) => n != null;
var d = z.any().refine((n) => y(n));
var b = z.enum(["ADD_ACCOUNT"]);
var f = z.enum(["ADD_AUDIT_REPORT"]);
var _ = z.enum(["ADD_COMMENT"]);
var A = z.enum(["ADD_LINE_ITEM"]);
var j = z.enum(["ADD_VESTING"]);
function u() {
  return z.object({
    __typename: z.literal("Account").optional(),
    address: z.string(),
    lineItems: z.array(m()),
    name: z.string()
  });
}
function I() {
  return z.object({
    address: z.string(),
    lineItems: z.array(z.lazy(() => p())).nullish(),
    name: z.string().nullish()
  });
}
function E() {
  return z.object({
    address: z.string(),
    lineItems: z.array(m()).nullish(),
    name: z.string().nullish()
  });
}
function D() {
  return z.object({
    input: z.lazy(() => T()),
    type: b
  });
}
function T() {
  return z.object({
    accounts: z.array(z.lazy(() => I()))
  });
}
function z2() {
  return z.object({
    input: z.lazy(() => C()),
    type: f
  });
}
function C() {
  return z.object({
    reports: z.array(F())
  });
}
function L() {
  return z.object({
    input: z.lazy(() => O()),
    type: _
  });
}
function O() {
  return z.object({
    comments: z.array(z.lazy(() => x()))
  });
}
function U() {
  return z.object({
    input: z.lazy(() => N()),
    type: A
  });
}
function N() {
  return z.object({
    account: z.string(),
    lineItems: z.array(z.lazy(() => p()))
  });
}
function R() {
  return z.object({
    input: z.lazy(() => v()),
    type: j
  });
}
function v() {
  return z.object({
    vesting: z.array(z.lazy(() => qt()))
  });
}
function e() {
  return z.object({
    __typename: z.literal("AuditReport").optional(),
    report: z.string(),
    status: o,
    timestamp: z.string().datetime()
  });
}
function M() {
  return z.object({
    report: z.lazy(() => rt()),
    status: o,
    timestamp: z.string().datetime().nullish()
  });
}
var o = z.enum(["Approved", "ApprovedWithComments", "Escalated", "NeedsAction"]);
function F() {
  return z.union([e(), M()]);
}
function Ht() {
  return z.object({
    __typename: z.literal("BudgetStatement").optional(),
    created: z.string().datetime(),
    data: V(),
    documentType: z.string(),
    lastModified: z.string().datetime(),
    name: z.string(),
    operations: z.array(d),
    revision: z.number()
  });
}
function Yt() {
  return z.union([D(), z2(), L(), U(), R(), H(), J(), X(), $(), nt(), Et(), Dt(), Tt(), zt(), Ct(), Ot(), Vt(), wt(), Bt(), Gt()]);
}
function V() {
  return z.object({
    __typename: z.literal("BudgetStatementData").optional(),
    accounts: z.array(u()),
    auditReports: z.array(e()),
    comments: z.array(a()),
    ftes: s().nullish(),
    month: z.string().nullish(),
    owner: S().nullish(),
    quoteCurrency: z.string().nullish(),
    vesting: z.array(g())
  });
}
function P() {
  return z.object({
    accounts: z.array(u()).nullish(),
    auditReports: z.array(e()).nullish(),
    comments: z.array(a()).nullish(),
    ftes: s().nullish(),
    month: z.string().nullish(),
    owner: S().nullish(),
    quoteCurrency: z.string().nullish(),
    vesting: z.array(g()).nullish()
  });
}
function Jt() {
  return z.object({
    created: z.string().datetime().nullish(),
    data: z.lazy(() => P()),
    documentType: z.string().nullish(),
    lastModified: z.string().datetime().nullish(),
    name: z.string().nullish(),
    revision: z.number().nullish()
  });
}
var r = z.enum(["Draft", "Escalated", "Final", "Review"]);
function a() {
  return z.object({
    __typename: z.literal("Comment").optional(),
    author: w(),
    comment: z.string(),
    key: z.string(),
    status: r,
    timestamp: z.string().datetime()
  });
}
function w() {
  return z.object({
    __typename: z.literal("CommentAuthor").optional(),
    id: z.string().nullish(),
    ref: z.string().nullish(),
    roleLabel: z.string().nullish(),
    username: z.string().nullish()
  });
}
function c() {
  return z.object({
    id: z.string().nullish(),
    ref: z.string().nullish(),
    roleLabel: z.string().nullish(),
    username: z.string().nullish()
  });
}
function x() {
  return z.object({
    author: z.lazy(() => c().nullish()),
    comment: z.string(),
    key: z.string().nullish(),
    status: r.nullish(),
    timestamp: z.string().datetime().nullish()
  });
}
function B() {
  return z.object({
    author: z.lazy(() => c().nullish()),
    comment: z.string().nullish(),
    key: z.string(),
    status: r.nullish(),
    timestamp: z.string().datetime().nullish()
  });
}
var k = z.enum(["DELETE_ACCOUNT"]);
var G = z.enum(["DELETE_AUDIT_REPORT"]);
var Q = z.enum(["DELETE_COMMENT"]);
var q = z.enum(["DELETE_LINE_ITEM"]);
var W = z.enum(["DELETE_VESTING"]);
function H() {
  return z.object({
    input: z.lazy(() => Y()),
    type: k
  });
}
function Y() {
  return z.object({
    accounts: z.array(z.string())
  });
}
function J() {
  return z.object({
    input: z.lazy(() => K()),
    type: G
  });
}
function K() {
  return z.object({
    reports: z.array(z.string())
  });
}
function X() {
  return z.object({
    input: z.lazy(() => Z()),
    type: Q
  });
}
function Z() {
  return z.object({
    comments: z.array(z.string())
  });
}
function $() {
  return z.object({
    input: z.lazy(() => tt()),
    type: q
  });
}
function tt() {
  return z.object({
    account: z.string(),
    lineItems: z.array(z.lazy(() => ct()))
  });
}
function nt() {
  return z.object({
    input: z.lazy(() => et()),
    type: W
  });
}
function et() {
  return z.object({
    vesting: z.array(z.string())
  });
}
function rt() {
  return z.object({
    data: z.string(),
    extension: z.string().nullish(),
    fileName: z.string().nullish(),
    mimeType: z.string()
  });
}
function s() {
  return z.object({
    __typename: z.literal("Ftes").optional(),
    forecast: z.array(it()),
    value: z.number()
  });
}
function it() {
  return z.object({
    __typename: z.literal("FtesForecast").optional(),
    month: z.string(),
    value: z.number()
  });
}
function ut() {
  return z.object({
    month: z.string(),
    value: z.number()
  });
}
function ot() {
  return z.object({
    forecast: z.array(z.lazy(() => ut())),
    value: z.number()
  });
}
var at = z.enum(["LOAD_STATE"]);
function m() {
  return z.object({
    __typename: z.literal("LineItem").optional(),
    actual: z.number().nullish(),
    budgetCap: z.number().nullish(),
    category: l().nullish(),
    comment: z.string().nullish(),
    forecast: z.array(i()),
    group: h().nullish(),
    headcountExpense: z.boolean(),
    payment: z.number().nullish()
  });
}
function l() {
  return z.object({
    __typename: z.literal("LineItemCategory").optional(),
    id: z.string(),
    ref: z.string(),
    title: z.string()
  });
}
function ct() {
  return z.object({
    category: z.string().nullish(),
    group: z.string().nullish()
  });
}
function i() {
  return z.object({
    __typename: z.literal("LineItemForecast").optional(),
    budgetCap: z.number(),
    month: z.string(),
    value: z.number()
  });
}
function h() {
  return z.object({
    __typename: z.literal("LineItemGroup").optional(),
    color: z.string(),
    id: z.string(),
    ref: z.string(),
    title: z.string()
  });
}
function p() {
  return z.object({
    actual: z.number().nullish(),
    budgetCap: z.number().nullish(),
    category: l().nullish(),
    comment: z.string().nullish(),
    forecast: z.array(i()).nullish(),
    group: h().nullish(),
    headcountExpense: z.boolean().nullish(),
    payment: z.number().nullish()
  });
}
function st() {
  return z.object({
    actual: z.number().nullish(),
    budgetCap: z.number().nullish(),
    category: z.string().nullish(),
    comment: z.string().nullish(),
    forecast: z.array(i()).nullish(),
    group: z.string().nullish(),
    headcountExpense: z.boolean().nullish(),
    payment: z.number().nullish()
  });
}
function mt() {
  return z.object({
    category: z.string().nullish(),
    group: z.string().nullish()
  });
}
function Kt() {
  return z.object({
    input: z.lazy(() => lt()),
    type: at
  });
}
function lt() {
  return z.object({
    operations: z.number(),
    state: z.lazy(() => ht())
  });
}
function ht() {
  return z.object({
    data: z.unknown().nullish(),
    name: z.string()
  });
}
function Xt() {
  return z.object({
    __typename: z.literal("Operation").optional(),
    hash: z.string(),
    index: z.number(),
    timestamp: z.string().datetime(),
    type: z.string()
  });
}
function S() {
  return z.object({
    __typename: z.literal("Owner").optional(),
    id: z.string().nullish(),
    ref: z.string().nullish(),
    title: z.string().nullish()
  });
}
function pt() {
  return z.object({
    id: z.string().nullish(),
    ref: z.string().nullish(),
    title: z.string().nullish()
  });
}
var St = z.enum(["PRUNE"]);
function Zt() {
  return z.object({
    input: z.lazy(() => gt()),
    type: St
  });
}
function gt() {
  return z.object({
    end: z.number().nullish(),
    start: z.number().nullish()
  });
}
var yt = z.enum(["REDO"]);
function $t() {
  return z.object({
    input: z.number(),
    type: yt
  });
}
var dt = z.enum(["SET_FTES"]);
var bt = z.enum(["SET_MONTH"]);
var ft = z.enum(["SET_NAME"]);
var _t = z.enum(["SET_OWNER"]);
var At = z.enum(["SET_QUOTE_CURRENCY"]);
var jt = z.enum(["SORT_ACCOUNTS"]);
var It = z.enum(["SORT_LINE_ITEMS"]);
function Et() {
  return z.object({
    input: z.lazy(() => ot()),
    type: dt
  });
}
function Dt() {
  return z.object({
    input: z.string(),
    type: bt
  });
}
function tn() {
  return z.object({
    input: z.string(),
    type: ft
  });
}
function nn() {
  return z.object({
    __typename: z.literal("SetNameOperation").optional(),
    hash: z.string(),
    index: z.number(),
    input: z.string(),
    timestamp: z.string().datetime(),
    type: z.string()
  });
}
function Tt() {
  return z.object({
    input: z.lazy(() => pt()),
    type: _t
  });
}
function zt() {
  return z.object({
    input: z.string(),
    type: At
  });
}
function Ct() {
  return z.object({
    input: z.lazy(() => Lt()),
    type: jt
  });
}
function Lt() {
  return z.object({
    accounts: z.array(z.string())
  });
}
function Ot() {
  return z.object({
    input: z.lazy(() => Ut()),
    type: It
  });
}
function Ut() {
  return z.object({
    account: z.string(),
    lineItems: z.array(z.lazy(() => mt()))
  });
}
var Nt = z.enum(["UNDO"]);
var Rt = z.enum(["UPDATE_ACCOUNT"]);
var vt = z.enum(["UPDATE_COMMENT"]);
var Mt = z.enum(["UPDATE_LINE_ITEM"]);
var Ft = z.enum(["UPDATE_VESTING"]);
function en() {
  return z.object({
    input: z.number(),
    type: Nt
  });
}
function Vt() {
  return z.object({
    input: z.lazy(() => Pt()),
    type: Rt
  });
}
function Pt() {
  return z.object({
    accounts: z.array(z.lazy(() => E()))
  });
}
function wt() {
  return z.object({
    input: z.lazy(() => xt()),
    type: vt
  });
}
function xt() {
  return z.object({
    comments: z.array(z.lazy(() => B()))
  });
}
function Bt() {
  return z.object({
    input: z.lazy(() => kt()),
    type: Mt
  });
}
function kt() {
  return z.object({
    account: z.string(),
    lineItems: z.array(z.lazy(() => st()))
  });
}
function Gt() {
  return z.object({
    input: z.lazy(() => Qt()),
    type: Ft
  });
}
function Qt() {
  return z.object({
    vesting: z.array(z.lazy(() => Wt()))
  });
}
function g() {
  return z.object({
    __typename: z.literal("Vesting").optional(),
    amount: z.string(),
    amountOld: z.string(),
    comment: z.string(),
    currency: z.string(),
    date: z.string(),
    key: z.string(),
    vested: z.boolean()
  });
}
function qt() {
  return z.object({
    amount: z.string().nullish(),
    amountOld: z.string().nullish(),
    comment: z.string().nullish(),
    currency: z.string().nullish(),
    date: z.string().nullish(),
    key: z.string().nullish(),
    vested: z.boolean().nullish()
  });
}
function Wt() {
  return z.object({
    amount: z.string().nullish(),
    amountOld: z.string().nullish(),
    comment: z.string().nullish(),
    currency: z.string().nullish(),
    date: z.string().nullish(),
    key: z.string(),
    vested: z.boolean().nullish()
  });
}
var rn = Object.freeze(Object.defineProperty({
  __proto__: null,
  AccountInputSchema: I,
  AccountSchema: u,
  AccountUpdateInputSchema: E,
  AddAccountActionSchema: D,
  AddAccountInputSchema: T,
  AddAuditReportActionSchema: z2,
  AddAuditReportInputSchema: C,
  AddCommentActionSchema: L,
  AddCommentInputSchema: O,
  AddLineItemActionSchema: U,
  AddLineItemInputSchema: N,
  AddVestingActionSchema: R,
  AddVestingInputSchema: v,
  Add_AccountSchema: b,
  Add_Audit_ReportSchema: f,
  Add_CommentSchema: _,
  Add_Line_ItemSchema: A,
  Add_VestingSchema: j,
  AuditReportInputSchema: M,
  AuditReportSchema: e,
  AuditReportStatusSchema: o,
  AuditReportUnionSchema: F,
  BudgetStatementActionSchema: Yt,
  BudgetStatementDataInputSchema: P,
  BudgetStatementDataSchema: V,
  BudgetStatementInputSchema: Jt,
  BudgetStatementSchema: Ht,
  BudgetStatusSchema: r,
  CommentAuthorInputSchema: c,
  CommentAuthorSchema: w,
  CommentInputSchema: x,
  CommentSchema: a,
  CommentUpdateInputSchema: B,
  DeleteAccountActionSchema: H,
  DeleteAccountInputSchema: Y,
  DeleteAuditReportActionSchema: J,
  DeleteAuditReportInputSchema: K,
  DeleteCommentActionSchema: X,
  DeleteCommentInputSchema: Z,
  DeleteLineItemActionSchema: $,
  DeleteLineItemInputSchema: tt,
  DeleteVestingActionSchema: nt,
  DeleteVestingInputSchema: et,
  Delete_AccountSchema: k,
  Delete_Audit_ReportSchema: G,
  Delete_CommentSchema: Q,
  Delete_Line_ItemSchema: q,
  Delete_VestingSchema: W,
  DocumentFileInputSchema: rt,
  FtesForecastInputSchema: ut,
  FtesForecastSchema: it,
  FtesInputSchema: ot,
  FtesSchema: s,
  LineItemCategorySchema: l,
  LineItemDeleteInputSchema: ct,
  LineItemForecastSchema: i,
  LineItemGroupSchema: h,
  LineItemInputSchema: p,
  LineItemSchema: m,
  LineItemUpdateInputSchema: st,
  LineItemsSortInputSchema: mt,
  LoadStateActionInputSchema: lt,
  LoadStateActionSchema: Kt,
  LoadStateActionStateInputSchema: ht,
  Load_StateSchema: at,
  OperationSchema: Xt,
  OwnerInputSchema: pt,
  OwnerSchema: S,
  PruneActionInputSchema: gt,
  PruneActionSchema: Zt,
  PruneSchema: St,
  RedoActionSchema: $t,
  RedoSchema: yt,
  SetFtesActionSchema: Et,
  SetMonthActionSchema: Dt,
  SetNameActionSchema: tn,
  SetNameOperationSchema: nn,
  SetOwnerActionSchema: Tt,
  SetQuoteCurrencyActionSchema: zt,
  Set_FtesSchema: dt,
  Set_MonthSchema: bt,
  Set_NameSchema: ft,
  Set_OwnerSchema: _t,
  Set_Quote_CurrencySchema: At,
  SortAccountsActionSchema: Ct,
  SortAccountsInputSchema: Lt,
  SortLineItemsActionSchema: Ot,
  SortLineItemsInputSchema: Ut,
  Sort_AccountsSchema: jt,
  Sort_Line_ItemsSchema: It,
  UndoActionSchema: en,
  UndoSchema: Nt,
  UpdateAccountActionSchema: Vt,
  UpdateAccountInputSchema: Pt,
  UpdateCommentActionSchema: wt,
  UpdateCommentInputSchema: xt,
  UpdateLineItemActionSchema: Bt,
  UpdateLineItemInputSchema: kt,
  UpdateVestingActionSchema: Gt,
  UpdateVestingInputSchema: Qt,
  Update_AccountSchema: Rt,
  Update_CommentSchema: vt,
  Update_Line_ItemSchema: Mt,
  Update_VestingSchema: Ft,
  VestingInputSchema: qt,
  VestingSchema: g,
  VestingUpdateInputSchema: Wt,
  definedNonNullAnySchema: d,
  isDefinedNonNullAny: y
}, Symbol.toStringTag, { value: "Module" }));
Object.freeze(Object.defineProperty({
  __proto__: null,
  z: rn
}, Symbol.toStringTag, { value: "Module" }));

const ADD_ACCOUNT = "ADD_ACCOUNT";
const UPDATE_ACCOUNT = "UPDATE_ACCOUNT";
const DELETE_ACCOUNT = "DELETE_ACCOUNT";
const SORT_ACCOUNTS = "SORT_ACCOUNTS";

const ADD_AUDIT_REPORT = "ADD_AUDIT_REPORT";
const DELETE_AUDIT_REPORT = "DELETE_AUDIT_REPORT";
function isAuditReport(audit) {
  return typeof audit.report === "string" && audit.report.startsWith("attachment://");
}

const SET_OWNER = "SET_OWNER";
const SET_MONTH = "SET_MONTH";
const SET_QUOTE_CURRENCY = "SET_QUOTE_CURRENCY";
const SET_FTES = "SET_FTES";

const ADD_COMMENT = "ADD_COMMENT";
const UPDATE_COMMENT = "UPDATE_COMMENT";
const DELETE_COMMENT = "DELETE_COMMENT";

const ADD_LINE_ITEM = "ADD_LINE_ITEM";
const UPDATE_LINE_ITEM = "UPDATE_LINE_ITEM";
const DELETE_LINE_ITEM = "DELETE_LINE_ITEM";
const SORT_LINE_ITEMS = "SORT_LINE_ITEMS";

const ADD_VESTING = "ADD_VESTING";
const UPDATE_VESTING = "UPDATE_VESTING";
const DELETE_VESTING = "DELETE_VESTING";

const createBudgetStatement = (initialState) => createDocument({
  documentType: "powerhouse/budget-statement",
  ...initialState,
  data: {
    owner: {
      ref: null,
      id: null,
      title: null
    },
    month: null,
    quoteCurrency: null,
    vesting: [],
    ftes: null,
    accounts: [],
    auditReports: [],
    comments: [],
    ...initialState?.data
  }
});
const createAccount = (input) => ({
  ...input,
  name: input.name ?? "",
  lineItems: input.lineItems?.map(createLineItem) ?? new Array()
});
const createLineItem = (input) => ({
  budgetCap: null,
  payment: null,
  actual: null,
  comment: null,
  ...input,
  forecast: input.forecast?.sort((f1, f2) => f1.month.localeCompare(f2.month)) ?? new Array(),
  headcountExpense: input.headcountExpense ?? false,
  group: input.group ?? null,
  category: input.category ?? null
});
const saveBudgetStatementToFile = (document, path, name) => {
  return saveToFile(document, path, "phbs", name);
};
const loadBudgetStatementFromFile = async (path) => {
  const state = await loadFromFile(
    path,
    reducer
  );
  const auditReports = state.data.auditReports;
  if (!auditReports.length) {
    return state;
  }
  const file = readFile(path);
  const zip = new JSZip();
  await zip.loadAsync(file);
  const fileRegistry = { ...state.fileRegistry };
  await Promise.all(
    auditReports.map(async (audit) => {
      const path2 = audit.report.slice("attachment://".length);
      const file2 = await zip.file(path2);
      if (!file2) {
        throw new Error(`Attachment ${audit.report} not found`);
      }
      const data = await file2.async("base64");
      const { mimeType, extension, fileName } = JSON.parse(file2.comment);
      fileRegistry[audit.report] = {
        data,
        mimeType,
        extension,
        fileName
      };
    })
  );
  return { ...state, fileRegistry };
};
const loadBudgetStatementFromInput = async (input) => {
  const state = await loadFromInput(
    input,
    reducer
  );
  const auditReports = state.data.auditReports;
  if (!auditReports.length) {
    return state;
  }
  const zip = new JSZip();
  await zip.loadAsync(input);
  const fileRegistry = { ...state.fileRegistry };
  await Promise.all(
    auditReports.map(async (audit) => {
      const path = audit.report.slice("attachment://".length);
      const file = await zip.file(path);
      if (!file) {
        throw new Error(`Attachment ${audit.report} not found`);
      }
      const data = await file.async("base64");
      const { mimeType, extension, fileName } = JSON.parse(file.comment);
      fileRegistry[audit.report] = {
        data,
        mimeType,
        extension,
        fileName
      };
    })
  );
  return { ...state, fileRegistry };
};
const saveBudgetStatementToFileHandle = async (document, input) => {
  const zip = await createZip(document);
  const blob = await zip.generateAsync({ type: "blob" });
  const writable = await input.createWritable();
  await writable.write(blob);
  await writable.close();
};

var utils = /*#__PURE__*/Object.freeze({
  __proto__: null,
  createAccount: createAccount,
  createBudgetStatement: createBudgetStatement,
  createLineItem: createLineItem,
  loadBudgetStatementFromFile: loadBudgetStatementFromFile,
  loadBudgetStatementFromInput: loadBudgetStatementFromInput,
  saveBudgetStatementToFile: saveBudgetStatementToFile,
  saveBudgetStatementToFileHandle: saveBudgetStatementToFileHandle
});

const addAccountOperation = (state, action) => {
  action.input.accounts.forEach((input) => {
    if (state.data.accounts.find(
      (account) => account.address === input.address
    )) {
      throw new Error(
        `Account with address ${input.address} already exists!`
      );
    }
    state.data.accounts.push(createAccount(input));
  });
};
const updateAccountOperation = (state, action) => {
  state.data.accounts = state.data.accounts.map((account) => {
    const accountUpdate = action.input.accounts.find(
      (a) => a.address === account.address
    );
    return {
      ...account,
      lineItems: accountUpdate?.lineItems ?? account.lineItems,
      name: accountUpdate?.name ?? account.name
    };
  });
};
const deleteAccountOperation = (state, action) => {
  state.data.accounts = state.data.accounts.filter(
    (account) => !action.input.accounts.find((address) => address === account.address)
  );
};
const sortAccountsOperation = (state, action) => {
  state.data.accounts.sort((a, b) => {
    const index1 = action.input.accounts.indexOf(a.address);
    const index2 = action.input.accounts.indexOf(b.address);
    return (index1 > -1 ? index1 : Infinity) - (index2 > -1 ? index2 : Infinity);
  });
};

function checkDuplicatedReport(state, report) {
  if (state.data.auditReports.find((audit) => audit.report === report)) {
    throw new Error(`Audit with report ${report} already exists`);
  }
}
const addAuditReportOperation = (state, action) => {
  const operation = state.operations[state.operations.length - 1];
  action.input.reports.forEach((audit, index) => {
    if (isAuditReport(audit)) {
      checkDuplicatedReport(state, audit.report);
      state.data.auditReports.push(audit);
    } else {
      const hash = hashAttachment(audit.report.data);
      const attachmentKey = `attachment://audits/${hash}`;
      checkDuplicatedReport(state, attachmentKey);
      state.fileRegistry[attachmentKey] = { ...audit.report };
      state.data.auditReports.push({
        timestamp: audit.timestamp ?? (/* @__PURE__ */ new Date()).toISOString(),
        status: audit.status,
        report: attachmentKey
      });
      operation.input.reports[index].report = attachmentKey;
    }
  });
};
const deleteAuditReportOperation = (state, action) => {
  action.input.reports.forEach((report) => {
    const index = state.data.auditReports.findIndex(
      (audit) => audit.report === report
    );
    if (index > -1) {
      state.data.auditReports.splice(index, 1);
    }
  });
};

const setOwnerOperation = (state, action) => {
  state.data.owner = {
    id: action.input.id ?? null,
    ref: action.input.ref ?? null,
    title: action.input.title ?? null
  };
};
const setMonthOperation = (state, action) => {
  state.data.month = action.input;
};
const setQuoteCurrencyOperation = (state, action) => {
  state.data.quoteCurrency = action.input;
};
const setFtesOperation = (state, action) => {
  state.data.ftes = action.input;
  state.data.ftes?.forecast.sort(
    (f1, f2) => f1.month.localeCompare(f2.month)
  );
};

function isEqual(lineItemInput, lineItem) {
  return lineItemInput.category === lineItem.category?.id && lineItemInput.group === lineItem.group?.id;
}
const addLineItemOperation = (state, action) => {
  const account = state.data.accounts.find(
    (a) => a.address === action.input.account
  );
  if (!account) {
    throw new Error(
      `Account with address ${action.input.account} not found`
    );
  }
  action.input.lineItems.forEach((input) => {
    if (account.lineItems.find(
      (item) => input.category?.id === item.category?.id && input.group?.id === item.group?.id
    )) {
      throw new Error(
        `Line item with category '${input.category?.id ?? "null"}' and group '${input.group?.id ?? "null"}' already exists`
      );
    }
    account.lineItems.push(createLineItem(input));
  });
};
const updateLineItemOperation = (state, action) => {
  const account = state.data.accounts.find(
    (a) => a.address === action.input.account
  );
  if (!account) {
    throw new Error(
      `Account with address ${action.input.account} not found`
    );
  }
  account.lineItems = account.lineItems.map((lineItem) => {
    const input = action.input.lineItems.find((l) => isEqual(l, lineItem));
    if (!input) {
      return lineItem;
    } else {
      return {
        ...lineItem,
        ...input,
        category: lineItem.category,
        headcountExpense: input.headcountExpense ?? false,
        group: lineItem.group,
        forecast: (input.forecast ?? lineItem.forecast).sort((f1, f2) => f1.month.localeCompare(f2.month))
      };
    }
  });
};
const deleteLineItemOperation = (state, action) => {
  const account = state.data.accounts.find(
    (a) => a.address === action.input.account
  );
  if (!account) {
    throw new Error(
      `Account with address ${action.input.account} not found`
    );
  }
  account.lineItems = account.lineItems.filter(
    (lineItem) => !action.input.lineItems.find((l) => isEqual(l, lineItem))
  );
};
const sortLineItemsOperation = (state, action) => {
  const account = state.data.accounts.find(
    (a) => a.address === action.input.account
  );
  if (!account) {
    throw new Error(
      `Account with address ${action.input.account} not found`
    );
  }
  account.lineItems.sort((a, b) => {
    const index1 = action.input.lineItems.findIndex((l) => isEqual(l, a));
    const index2 = action.input.lineItems.findIndex((l) => isEqual(l, b));
    return (index1 > -1 ? index1 : Infinity) - (index2 > -1 ? index2 : Infinity);
  });
};

const sortComment = (a, b) => a.timestamp < b.timestamp ? -1 : 1;
const addCommentOperation = (state, action) => {
  action.input.comments.forEach((input) => {
    const key = input.key ?? hashKey();
    const index = state.data.comments.findIndex((c) => c.key === input.key);
    if (index > -1) {
      throw new Error(`Comment with key ${key} already exists`);
    }
    state.data.comments.push({
      key,
      author: {
        ref: null,
        id: null,
        username: null,
        roleLabel: null,
        ...input.author
      },
      comment: input.comment,
      timestamp: input.timestamp || (/* @__PURE__ */ new Date()).toISOString(),
      status: input.status ?? "Draft"
    });
  });
  state.data.comments.sort(sortComment);
};
const updateCommentOperation = (state, action) => {
  action.input.comments.forEach((input) => {
    const index = state.data.comments.findIndex((c) => c.key === input.key);
    if (index === -1) {
      return;
    }
    const comment = state.data.comments[index];
    state.data.comments[index] = {
      ...comment,
      ...input,
      author: {
        id: input.author?.id ?? comment.author.id,
        ref: input.author?.ref ?? comment.author.ref,
        roleLabel: input.author?.roleLabel ?? comment.author.roleLabel,
        username: input.author?.username ?? comment.author.username
      },
      comment: input.comment ?? comment.comment,
      timestamp: input.timestamp ?? (/* @__PURE__ */ new Date()).toISOString(),
      status: input.status ?? comment.status
    };
  });
  state.data.comments.sort(sortComment);
};
const deleteCommentOperation = (state, action) => {
  state.data.comments = state.data.comments.filter(
    (comment) => !action.input.comments.includes(comment.key)
  );
};

const sortVesting = (a, b) => a.date < b.date ? -1 : 1;
const addVestingOperation = (state, action) => {
  action.input.vesting.forEach((input) => {
    const key = input.key ?? hashKey();
    const index = state.data.vesting.findIndex((v) => v.key === input.key);
    if (index > -1) {
      throw new Error(`Vesting with key ${key} already exists`);
    }
    state.data.vesting.push({
      ...input,
      key,
      date: input.date ?? "",
      amount: input.amount ?? "",
      amountOld: input.amountOld ?? input.amount ?? "",
      comment: input.comment ?? "",
      currency: input.currency ?? "",
      vested: input.vested ?? false
    });
  });
  state.data.vesting.sort(sortVesting);
};
const updateVestingOperation = (state, action) => {
  action.input.vesting.forEach((input) => {
    const index = state.data.vesting.findIndex((v) => v.key === input.key);
    if (index === -1) {
      return;
    }
    const vesting = state.data.vesting[index];
    state.data.vesting[index] = {
      ...vesting,
      ...input,
      amount: input.amount ?? vesting.amount,
      amountOld: input.amountOld ?? vesting.amountOld,
      comment: input.comment ?? vesting.comment,
      currency: input.currency ?? vesting.currency,
      date: input.date ?? vesting.date,
      vested: input.vested ?? vesting.vested
    };
  });
  state.data.vesting.sort(sortVesting);
};
const deleteVestingOperation = (state, action) => {
  state.data.vesting = state.data.vesting.filter(
    (vesting) => !action.input.vesting.includes(vesting.key)
  );
};

const reducer = createReducer((state, action) => {
  if (isBaseAction(action)) {
    return state;
  }
  rn.BudgetStatementActionSchema().parse(action);
  switch (action.type) {
    case SET_OWNER:
      return setOwnerOperation(state, action);
    case SET_MONTH:
      return setMonthOperation(state, action);
    case SET_QUOTE_CURRENCY:
      return setQuoteCurrencyOperation(state, action);
    case SET_FTES:
      return setFtesOperation(state, action);
    case ADD_ACCOUNT:
      return addAccountOperation(state, action);
    case UPDATE_ACCOUNT:
      return updateAccountOperation(state, action);
    case DELETE_ACCOUNT:
      return deleteAccountOperation(state, action);
    case SORT_ACCOUNTS:
      return sortAccountsOperation(state, action);
    case ADD_LINE_ITEM:
      return addLineItemOperation(state, action);
    case UPDATE_LINE_ITEM:
      return updateLineItemOperation(state, action);
    case DELETE_LINE_ITEM:
      return deleteLineItemOperation(state, action);
    case SORT_LINE_ITEMS:
      return sortLineItemsOperation(state, action);
    case ADD_AUDIT_REPORT:
      return addAuditReportOperation(state, action);
    case DELETE_AUDIT_REPORT:
      return deleteAuditReportOperation(state, action);
    case ADD_VESTING:
      return addVestingOperation(state, action);
    case UPDATE_VESTING:
      return updateVestingOperation(state, action);
    case DELETE_VESTING:
      return deleteVestingOperation(state, action);
    case ADD_COMMENT:
      return addCommentOperation(state, action);
    case UPDATE_COMMENT:
      return updateCommentOperation(state, action);
    case DELETE_COMMENT:
      return deleteCommentOperation(state, action);
    default:
      return state;
  }
});

const addAccount = (accounts) => createAction(
  ADD_ACCOUNT,
  {
    accounts: accounts.map(createAccount)
  },
  rn.AddAccountActionSchema
);
const updateAccount = (accounts) => createAction(
  UPDATE_ACCOUNT,
  { accounts },
  rn.UpdateAccountActionSchema
);
const deleteAccount = (accounts) => createAction(
  DELETE_ACCOUNT,
  { accounts },
  rn.DeleteAccountActionSchema
);
const sortAccounts = (accounts) => createAction(
  SORT_ACCOUNTS,
  { accounts },
  rn.SortAccountsActionSchema
);

const addAuditReport = (reports) => {
  const newTimestamp = /* @__PURE__ */ new Date();
  const newReports = reports.map(({ timestamp, report, status }) => ({
    report,
    timestamp: timestamp ?? newTimestamp.toISOString(),
    status
  }));
  return createAction(
    ADD_AUDIT_REPORT,
    {
      reports: newReports
    },
    rn.AddAuditReportActionSchema
  );
};
const deleteAuditReport = (reports) => createAction(
  DELETE_AUDIT_REPORT,
  { reports },
  rn.DeleteAuditReportActionSchema
);

const setOwner = (owner) => createAction(SET_OWNER, owner, rn.SetOwnerActionSchema);
const setMonth = (month) => createAction(SET_MONTH, month, rn.SetMonthActionSchema);
const setQuoteCurrency = (currency) => createAction(
  SET_QUOTE_CURRENCY,
  currency,
  rn.SetQuoteCurrencyActionSchema
);
const setFtes = (ftes) => createAction(SET_FTES, ftes, rn.SetFtesActionSchema);

const addComment = (comments) => createAction(
  ADD_COMMENT,
  { comments },
  rn.AddCommentActionSchema
);
const updateComment = (comments) => createAction(
  UPDATE_COMMENT,
  { comments },
  rn.UpdateCommentActionSchema
);
const deleteComment = (comments) => createAction(
  DELETE_COMMENT,
  { comments },
  rn.DeleteCommentActionSchema
);

const addLineItem = (account, lineItems) => createAction(
  ADD_LINE_ITEM,
  {
    account,
    lineItems: lineItems.map(createLineItem)
  },
  rn.AddLineItemActionSchema
);
const updateLineItem = (account, lineItems) => createAction(
  UPDATE_LINE_ITEM,
  {
    account,
    lineItems
  },
  rn.UpdateLineItemActionSchema
);
const deleteLineItem = (account, lineItems) => createAction(
  DELETE_LINE_ITEM,
  {
    account,
    lineItems
  },
  rn.DeleteLineItemActionSchema
);
const sortLineItems = (account, lineItems) => createAction(
  SORT_LINE_ITEMS,
  {
    account,
    lineItems
  },
  rn.SortLineItemsActionSchema
);

const addVesting = (vesting) => createAction(
  ADD_VESTING,
  { vesting },
  rn.AddVestingActionSchema
);
const updateVesting = (vesting) => createAction(
  UPDATE_VESTING,
  { vesting },
  rn.UpdateVestingActionSchema
);
const deleteVesting = (vesting) => createAction(
  DELETE_VESTING,
  { vesting },
  rn.DeleteVestingActionSchema
);

class AccountObject extends BaseDocument {
  /**
   * Adds one or more accounts to the budget statement.
   * @param accounts An array of AccountInput objects to add.
   *
   * @group Account
   */
  addAccount(accounts) {
    const action = addAccount(accounts);
    return this.dispatch(action);
  }
  /**
   * Updates one or more existing accounts in the budget statement.
   * @param accounts An array of AccountInput objects to update.
   *
   * @group Account
   */
  updateAccount(accounts) {
    return this.dispatch(updateAccount(accounts));
  }
  /**
   * Deletes one or more accounts from the budget statement.
   * @param accounts An array of addresses of the accounts to delete.
   *
   * @group Account
   */
  deleteAccount(accounts) {
    return this.dispatch(deleteAccount(accounts));
  }
  /**
   * Sorts the accounts inthe budget statement.
   * @param accounts An array of addresses of the accounts to sort.
   *
   * @group Account
   */
  sortAccounts(accounts) {
    return this.dispatch(sortAccounts(accounts));
  }
  /**
   * Returns an array of all accounts in the budget statement.
   *
   * @group Account
   */
  get accounts() {
    return this._state.data.accounts;
  }
  /**
   * Returns the Account object with the specified address.
   * @param address The address of the Account to retrieve.
   *
   * @group Account
   */
  getAccount(address) {
    return this.accounts.find((account) => account.address === address);
  }
}

class AuditObject extends BaseDocument {
  /**
   * Adds audit reports to the budget statement.
   * @param reports - An array of audit report objects to add.
   *
   * @group Audit
   */
  addAuditReport(reports) {
    return this.dispatch(addAuditReport(reports));
  }
  /**
   * Deletes audit reports from the budget statement.
   * @param reports - An array of objects that contain the report attachment name of the audits items to be deleted.
   *
   * @group Audit
   */
  deleteAuditReport(reports) {
    return this.dispatch(deleteAuditReport(reports));
  }
  /**
   * Retrieves all audit reports from the budget statement.
   * @returns An array of audit report objects.
   *
   * @group Audit
   */
  getAuditReports() {
    return this._state.data.auditReports;
  }
  /**
   * Retrieves a specific audit report from the budget statement.
   * @param report - The name of the attachment of the report to be retrieved.
   * @returns The audit report object if it exists, or undefined if not.
   *
   * @group Audit
   */
  getAuditReport(report) {
    return this.getAuditReports().find((audit) => audit.report === report);
  }
}

class BaseObject extends BaseDocument {
  /**
   * Gets the month of the budget statement.
   * @category Budget Statement
   */
  get month() {
    return this._state.data.month;
  }
  /**
   * Gets the owner of the budget statement.
   * @category Budget Statement
   */
  get owner() {
    return this._state.data.owner;
  }
  /**
   * Gets the quote currency of the budget statement.
   * @category Budget Statement
   */
  get quoteCurrency() {
    return this._state.data.quoteCurrency;
  }
  get ftes() {
    return this._state.data.ftes;
  }
  setOwner(owner) {
    return this.dispatch(setOwner(owner));
  }
  setMonth(month) {
    return this.dispatch(setMonth(month));
  }
  setQuoteCurrency(currency) {
    return this.dispatch(setQuoteCurrency(currency));
  }
  setFtes(ftes) {
    return this.dispatch(setFtes(ftes));
  }
}

class CommentObject extends BaseDocument {
  addComment(comments) {
    return this.dispatch(addComment(comments));
  }
  updateComment(comments) {
    return this.dispatch(updateComment(comments));
  }
  deleteComment(comments) {
    return this.dispatch(deleteComment(comments));
  }
  get comments() {
    return this._state.data.comments;
  }
  getComment(key) {
    return this._state.data.comments.find((v) => v.key === key);
  }
}

class LineItemObject extends BaseDocument {
  /**
   * Adds a line item to the specified account.
   * @param account The address of the account to which the line item will be added.
   * @param lineItems An array of line item objects to be added to the account.
   *
   * @group Line Item
   */
  addLineItem(account, lineItems) {
    return this.dispatch(addLineItem(account, lineItems));
  }
  /**
   * Updates line items for the specified account.
   * @param account The address of the account for which line items will be updated.
   * @param lineItems An array of line item input objects to be updated.
   *
   * @group Line Item
   */
  updateLineItem(account, lineItems) {
    return this.dispatch(updateLineItem(account, lineItems));
  }
  /**
   * Deletes line items for the specified account.
   * @param account The address of the account for which line items will be deleted.
   * @param lineItems An array of objects that contain the category and group of the line items to be deleted.
   *
   * @group Line Item
   */
  deleteLineItem(account, lineItems) {
    return this.dispatch(deleteLineItem(account, lineItems));
  }
  /**
   * Sorts the line items of an account.
   *
   * @param account - The account containing the line items to sort.
   * @param lineItems - An array of line items to sort.
   * @group Line Item
   */
  sortLineItems(account, lineItems) {
    return this.dispatch(sortLineItems(account, lineItems));
  }
  /**
   * Retrieves line items for the specified account.
   * @param account The address of the account for which line items will be retrieved.
   * @returns An array of line item objects for the specified account, or undefined if the account does not exist.
   *
   * @group Line Item
   */
  getLineItems(account) {
    return this._state.data.accounts.find(
      ({ address }) => address === account
    )?.lineItems;
  }
  /**
   * Retrieves a specific line item for the specified account.
   * @param account The address of the account for which the line item will be retrieved.
   * @param lineItem An object that contains the category and group of the line item to be retrieved.
   * @returns The line item object that matches the specified category and group, or undefined if it does not exist.
   *
   * @group Line Item
   */
  getLineItem(account, lineItem) {
    return this.getLineItems(account)?.find(
      ({ category, group }) => category?.id === lineItem.category && group?.id === lineItem.group
    );
  }
}

class VestingObject extends BaseDocument {
  addVesting(vesting) {
    return this.dispatch(addVesting(vesting));
  }
  updateVesting(vesting) {
    return this.dispatch(updateVesting(vesting));
  }
  deleteVesting(vesting) {
    return this.dispatch(deleteVesting(vesting));
  }
  get vesting() {
    return this._state.data.vesting;
  }
  getVesting(key) {
    return this._state.data.vesting.find((v) => v.key === key);
  }
}

let BudgetStatement$2 = class BudgetStatement extends BaseDocument {
  /**
   * The file extension used to save budget statements.
   */
  static fileExtension = "phbs";
  /**
   *
   * Creates a new BudgetStatement instance.
   * @param initialState - An optional object representing the initial state of the BudgetStatement.
   */
  constructor(initialState) {
    super(reducer, createBudgetStatement(initialState));
  }
  /**
   * Saves the budget statement to a file.
   *
   * @param path The path to the file to save.
   * @returns A promise that resolves when the save operation completes.
   */
  saveToFile(path, name) {
    return super.saveToFile(path, BudgetStatement.fileExtension, name);
  }
  /**
   * Loads the budget statement from a file.
   *
   * @param path The path to the file to load.
   * @returns A promise that resolves with the loaded `BudgetStatement` instance.
   */
  loadFromFile(path) {
    return super.loadFromFile(path);
  }
  /**
   * Creates a new `BudgetStatement` instance from a file.
   *
   * @param path The path to the file to load.
   * @returns A promise that resolves with the loaded `BudgetStatement` instance.
   */
  static async fromFile(path) {
    const budgetStatement = new this();
    await budgetStatement.loadFromFile(path);
    return budgetStatement;
  }
};
applyMixins(BudgetStatement$2, [
  AccountObject,
  AuditObject,
  CommentObject,
  BaseObject,
  LineItemObject,
  VestingObject
]);

var gen = /*#__PURE__*/Object.freeze({
  __proto__: null,
  BudgetStatement: BudgetStatement$2,
  addAccount: addAccount,
  addAuditReport: addAuditReport,
  addComment: addComment,
  addLineItem: addLineItem,
  addVesting: addVesting,
  deleteAccount: deleteAccount,
  deleteAuditReport: deleteAuditReport,
  deleteComment: deleteComment,
  deleteLineItem: deleteLineItem,
  deleteVesting: deleteVesting,
  setFtes: setFtes,
  setMonth: setMonth,
  setOwner: setOwner,
  setQuoteCurrency: setQuoteCurrency,
  sortAccounts: sortAccounts,
  sortLineItems: sortLineItems,
  updateAccount: updateAccount,
  updateComment: updateComment,
  updateLineItem: updateLineItem,
  updateVesting: updateVesting
});

const { BudgetStatement, ...BudgetActions } = gen;
const actions = { ...BaseActions, ...BudgetActions };
var index = {
  actions,
  reducer,
  utils,
  BudgetStatement
};

var BudgetStatement$1 = /*#__PURE__*/Object.freeze({
  __proto__: null,
  BudgetStatement: BudgetStatement,
  actions: actions,
  default: index,
  reducer: reducer,
  utils: utils
});

export { BudgetStatement$1 as B, BudgetStatement as a, actions as b, index as i, reducer as r, utils as u };
//# sourceMappingURL=index-040395fe.js.map
