'use strict'

const sequelize = require('sequelize')
const GraphQLToolsTypes = require('graphql-tools-types')
const models = require('../models')
const bcrypt = require('bcryptjs')
const moment = require('moment')
const jwt = require('jsonwebtoken')
const fs = require('fs');
const path = require('path');
const nodemailer = require('nodemailer')
const crypto = require("crypto");
const AWS = require('aws-sdk')
const env = 'staging'

const PUBLIC_KEY = `-----BEGIN PUBLIC KEY-----
MIGeMA0GCSqGSIb3DQEBAQUAA4GMADCBiAKBgGv3i+Ft20rvm+ny6KaRj467ZKVK
4ahrmdlYtqaqvJM9DQLRq3Dyodk9+va85vSlzD63b9fCPyje3kroPJoiw/FAG/EZ
DPhvONgywhrK6f5g0yD+++Gkup5HXexr2x/T6D36nYiyzp8qAxHM61Chk+catNFf
eHKRi+pXU3UgM6GPAgMBAAE=
-----END PUBLIC KEY-----`

require('dotenv').config()
const Op = sequelize.Op

AWS.config.update({
  accessKeyId: 'AKIASMWFHZL2PCME4OAF',
  secretAccessKey: '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',
  region: 'us-east-2',
})
const s3 = new AWS.S3();

const updateCashInHand = async sale => {
  const totalExpense = await models.sales_expense.findOne({
    attributes: [
      [sequelize.fn('SUM', sequelize.col('amount')), 'total_amount']
    ],
    where: {
      sale_id: sale.id
    }
  })
  const totalExpenseAmount = totalExpense.dataValues.total_amount || 0.0

  const totalDesopit = await models.sales_deposit.findOne({
    attributes: [
      [sequelize.fn('SUM', sequelize.col('amount')), 'total_amount']
    ],
    where: {
      sale_id: sale.id
    }
  })
  const totalDesopitAmount = totalDesopit.dataValues.total_amount || 0.0
  const cashInHand = sale.cash - totalExpenseAmount - totalDesopitAmount

  await models.sale.update({
    cash_in_hand: cashInHand
  },
    {
      where: {
        id: sale.id
      }
    })
}

const createPeriod = (startDate, endDate) => {
  const startDisplay = startDate.format('MM/DD/YYYY')
  const endDisplay = endDate.format('MM/DD/YYYY')
  const start = startDate.format('YYYY-MM-DD')
  const end = endDate.format('YYYY-MM-DD')
  return {
    display: startDisplay + ' ― ' + endDisplay,
    period: start + '>' + end,
    start: start,
    end: end
  }
}

const weeklyDates = (year, payrollStartDay) => {
  var startDate = moment().year(year).startOf('year').startOf('week').add(payrollStartDay, 'day')
  var endDate = moment().year(year).startOf('year').endOf('week').add(payrollStartDay, 'day')
  var periods = []
  while (endDate.year() === year) {
    periods.push(createPeriod(startDate, endDate))
    startDate = startDate.add(1, 'week')
    endDate = endDate.add(1, 'week')
  }
  periods.push(createPeriod(startDate, endDate))
  return periods
}

const payrollPeriods = (year, payrollStartDay, payrollPeriod) => {
  var startDate = moment().year(year).startOf('year').startOf('week').add(payrollStartDay, 'day')
  var endDate = moment().year(year).startOf('year').endOf('week').add(payrollStartDay, 'day')
  var periods = []
  while (endDate.year() === year) {
    periods.push(createPeriod(startDate, endDate))
    startDate = startDate.add(payrollPeriod, 'week')
    endDate = endDate.add(payrollPeriod, 'week')
  }
  periods.push(createPeriod(startDate, endDate))
  return periods
}

const previousTotalCashInHand = async (unit_id, date) => {
  const cashInHand = await models.sale.findOne({
    attributes: [
      [sequelize.fn('SUM', sequelize.col('cash_in_hand')), 'total_cash_in_hand']
    ],
    where: {
      [Op.and]: [
        {
          sales_date: {
            [Op.lt]: date
          }
        },
        {
          unit_id: unit_id
        }
      ]
    }
  })
  return cashInHand.dataValues.total_cash_in_hand
}

const totalCashInHand = async (unit_id, date) => {
  const cashInHand = await models.sale.findOne({
    attributes: [
      [sequelize.fn('SUM', sequelize.col('cash_in_hand')), 'total_cash_in_hand']
    ],
    where: {
      [Op.and]: [
        {
          sales_date: {
            [Op.lte]: date
          }
        },
        {
          unit_id: unit_id
        }
      ]
    }
  })
  return cashInHand.dataValues.total_cash_in_hand
}

const aggregatedSales = async (unit_id, from, to) => {
  const periodSales = await models.sale.findAll({
    having: {
      [Op.and]: [
        {
          sales_date: {
            [Op.gte]: from
          }
        },
        {
          sales_date: {
            [Op.lte]: to
          }
        },
        {
          unit_id: unit_id
        }
      ]
    },
    raw: true
  })
  const fromMoment = moment(from)
  const toMoment = moment(to)

  let gross_sales = 0.0
  let tax = 0.0
  let net_sales = 0.0
  let net_sales_uber_eats = 0.0
  let tax_uber_eats = 0.0
  let net_sales_postmates = 0.0
  let tax_postmates = 0.0
  let credit_sales = 0.0
  let amex_credit_sales = 0.0
  let master_credit_sales = 0.0
  let discover_credit_sales = 0.0
  let visa_credit_sales = 0.0
  let debit_sales = 0.0
  let gift_card_redeem = 0.0
  let gift_card_sold = 0.0
  let donations = 0.0
  let cash = 0.0
  let rbi_mobile_app = 0.0
  let uber_eats = 0.0
  let grubhub = 0.0
  let doordash = 0.0
  let white_label = 0.0
  let postmates = 0.0
  let snackpass = 0.0
  let transactions = 0
  let voids = 0
  let voids_amount = 0.0
  let refunds = 0
  let refunds_amount = 0.0
  let discounts = 0
  let discounts_amount = 0.0

  periodSales.forEach((sales, i) => {
    gross_sales += sales.gross_sales
    tax += sales.tax
    net_sales += sales.net_sales
    net_sales_uber_eats += sales.net_sales_uber_eats
    tax_uber_eats += sales.tax_uber_eats
    net_sales_postmates += sales.net_sales_postmates
    tax_postmates += sales.tax_postmates
    credit_sales += sales.credit_sales
    amex_credit_sales += sales.amex_credit_sales
    master_credit_sales += sales.master_credit_sales
    discover_credit_sales += sales.discover_credit_sales
    visa_credit_sales += sales.visa_credit_sales
    debit_sales += sales.debit_sales
    gift_card_redeem += sales.gift_card_redeem
    gift_card_sold += sales.gift_card_sold
    donations += sales.donations
    cash += sales.cash
    rbi_mobile_app += sales.rbi_mobile_app
    uber_eats += sales.uber_eats
    grubhub += sales.grubhub
    doordash += sales.doordash
    white_label += sales.white_label
    postmates += sales.postmates
    snackpass += sales.snackpass
    transactions += sales.transactions
    voids += sales.voids
    voids_amount += sales.voids_amount
    refunds += sales.refunds
    refunds_amount += sales.refunds_amount
    discounts += sales.discounts
    discounts_amount += sales.discounts_amount
  })

  return {
    id: 10000000 * fromMoment.diff(toMoment, 'days') + 1000 * unit_id,
    from: fromMoment,
    to: toMoment,
    sale: {
      id: 0,
      gross_sales: gross_sales,
      tax: tax,
      net_sales: net_sales,
      net_sales_uber_eats: net_sales_uber_eats,
      tax_uber_eats: tax_uber_eats,
      net_sales_postmates: net_sales_postmates,
      tax_postmates: tax_postmates,
      credit_sales: credit_sales,
      amex_credit_sales: amex_credit_sales,
      master_credit_sales: master_credit_sales,
      discover_credit_sales: discover_credit_sales,
      visa_credit_sales: visa_credit_sales,
      debit_sales: debit_sales,
      gift_card_redeem: gift_card_redeem,
      gift_card_sold: gift_card_sold,
      donations: donations,
      cash: cash,
      rbi_mobile_app: rbi_mobile_app,
      uber_eats: uber_eats,
      grubhub: grubhub,
      doordash: doordash,
      white_label: white_label,
      postmates: postmates,
      snackpass: snackpass,
      transactions: transactions,
      voids: voids,
      voids_amount: voids_amount,
      refunds: refunds,
      refunds_amount: refunds_amount,
      discounts: discounts,
      discounts_amount: discounts_amount
    }
  }
}

const getUserDashboard = async (user_id, from, to) => {
  const unitIds = await models.unit_user.findAll({
    where: {
      user_id: user_id
    }
  }).map(u => u.unit_id)

  const saleIds = await models.sale.findAll({
    attributes: [
      'id',
    ],
    where: {
      [Op.and]: [
        {
          unit_id: unitIds
        },
        {
          sales_date: {
            [Op.gte]: from
          }
        },
        {
          sales_date: {
            [Op.lte]: to
          }
        }
      ]
    }
  }).map(s => s.id)

  const sales = await models.sale.findAll({
    group: ['sales_date'],
    attributes: [
      [sequelize.fn('sum', sequelize.col('net_sales')), 'net_sales'],
      [sequelize.fn('sum', sequelize.col('gross_sales')), 'gross_sales'],
      [sequelize.fn('sum', sequelize.col('tax')), 'tax'],
      [sequelize.fn('sum', sequelize.col('net_sales_uber_eats')), 'net_sales_uber_eats'],
      [sequelize.fn('sum', sequelize.col('tax_uber_eats')), 'tax_uber_eats'],
      [sequelize.fn('sum', sequelize.col('net_sales_postmates')), 'net_sales_postmates'],
      [sequelize.fn('sum', sequelize.col('tax_postmates')), 'tax_postmates'],
      [sequelize.fn('sum', sequelize.col('credit_sales')), 'credit_sales'],
      [sequelize.fn('sum', sequelize.col('amex_credit_sales')), 'amex_credit_sales'],
      [sequelize.fn('sum', sequelize.col('master_credit_sales')), 'master_credit_sales'],
      [sequelize.fn('sum', sequelize.col('discover_credit_sales')), 'discover_credit_sales'],
      [sequelize.fn('sum', sequelize.col('visa_credit_sales')), 'visa_credit_sales'],
      [sequelize.fn('sum', sequelize.col('debit_sales')), 'debit_sales'],
      [sequelize.fn('sum', sequelize.col('gift_card_redeem')), 'gift_card_redeem'],
      [sequelize.fn('sum', sequelize.col('gift_card_sold')), 'gift_card_sold'],
      [sequelize.fn('sum', sequelize.col('donations')), 'donations'],
      [sequelize.fn('sum', sequelize.col('cash')), 'cash'],
      [sequelize.fn('sum', sequelize.col('rbi_mobile_app')), 'rbi_mobile_app'],
      [sequelize.fn('sum', sequelize.col('uber_eats')), 'uber_eats'],
      [sequelize.fn('sum', sequelize.col('grubhub')), 'grubhub'],
      [sequelize.fn('sum', sequelize.col('doordash')), 'doordash'],
      [sequelize.fn('sum', sequelize.col('white_label')), 'white_label'],
      [sequelize.fn('sum', sequelize.col('postmates')), 'postmates'],
      [sequelize.fn('sum', sequelize.col('snackpass')), 'snackpass'],
      [sequelize.fn('sum', sequelize.col('transactions')), 'transactions'],
    ],
    where: {
      id: saleIds
    }
  })

  const expenses = await models.sales_expense.findAll({
    group: ['sale_id'],
    attributes: [
      [sequelize.fn('sum', sequelize.col('amount')), 'amount'],
    ],
    where: {
      [Op.and]: [
        {
          sale_id: saleIds
        }
      ]
    }
  })

  const deposits = await models.sales_deposit.findAll({
    group: ['sale_id'],
    attributes: [
      [sequelize.fn('sum', sequelize.col('amount')), 'amount'],
    ],
    where: {
      [Op.and]: [
        {
          sale_id: saleIds
        }
      ]
    }
  })

  const deliveries = await models.sales_food_delivery.findAll({
    group: ['sale_id'],
    attributes: [
      [sequelize.fn('sum', sequelize.col('amount')), 'amount'],
    ],
    where: {
      [Op.and]: [
        {
          sale_id: saleIds
        }
      ]
    }
  })

  const payrolls = await models.payroll.findAll({
    attributes: [
      'id',
      'period',
      'status',
      'unit_id',
      [sequelize.fn('STR_TO_DATE', sequelize.fn('SUBSTRING_INDEX', sequelize.col('period'), ">", -1), "%Y-%c-%d"), 'payroll_end']
    ],
    where: {
      unit_id: unitIds
    },
    having: {
      [Op.and]: [
        {
          payroll_end: {
            [Op.gte]: from.format("YYYY-MM-DD")
          }
        },
        {
          payroll_end: {
            [Op.lte]: to.format("YYYY-MM-DD")
          }
        }
      ]
    }
  })

  const gross_wages = await models.employee_payroll.findAll({
    group: ['payroll_id'],
    attributes: [
      [sequelize.fn('sum', sequelize.col('gross_wages')), 'gross_wages'],
    ],
    where: {
      [Op.and]: [
        {
          payroll_id: payrolls.map(s => s.id)
        }
      ]
    }
  })

  return {
    total_stores: unitIds.length,
    total_net_sales: sales.map(s => s.net_sales).reduce((a, b) => a + b, 0.0),
    total_gross_sales: sales.map(s => s.gross_sales).reduce((a, b) => a + b, 0.0),
    total_net_sales: sales.map(s => s.net_sales).reduce((a, b) => a + b, 0.0),
    total_net_sales_uber_eats: sales.map(s => s.net_sales_uber_eats).reduce((a, b) => a + b, 0.0),
    total_tax_uber_eats: sales.map(s => s.tax_uber_eats).reduce((a, b) => a + b, 0.0),
    total_net_sales_postmates: sales.map(s => s.net_sales_postmates).reduce((a, b) => a + b, 0.0),
    total_tax_postmates: sales.map(s => s.tax_postmates).reduce((a, b) => a + b, 0.0),
    total_credit_sales: sales.map(s => s.credit_sales).reduce((a, b) => a + b, 0.0),
    total_amex_credit_sales: sales.map(s => s.amex_credit_sales).reduce((a, b) => a + b, 0.0),
    total_master_credit_sales: sales.map(s => s.master_credit_sales).reduce((a, b) => a + b, 0.0),
    total_discover_credit_sales: sales.map(s => s.discover_credit_sales).reduce((a, b) => a + b, 0.0),
    total_visa_credit_sales: sales.map(s => s.visa_credit_sales).reduce((a, b) => a + b, 0.0),
    total_debit_sales: sales.map(s => s.debit_sales).reduce((a, b) => a + b, 0.0),
    total_gift_card_redeem: sales.map(s => s.gift_card_redeem).reduce((a, b) => a + b, 0.0),
    total_gift_card_sold: sales.map(s => s.gift_card_sold).reduce((a, b) => a + b, 0.0),
    total_donations: sales.map(s => s.donations).reduce((a, b) => a + b, 0.0),
    total_cash_sales: sales.map(s => s.cash).reduce((a, b) => a + b, 0.0),
    total_rbi_mobile_app: sales.map(s => s.rbi_mobile_app).reduce((a, b) => a + b, 0.0),
    total_uber_eats: sales.map(s => s.uber_eats).reduce((a, b) => a + b, 0.0),
    total_grubhub: sales.map(s => s.grubhub).reduce((a, b) => a + b, 0.0),
    total_doordash: sales.map(s => s.doordash).reduce((a, b) => a + b, 0.0),
    total_white_label: sales.map(s => s.white_label).reduce((a, b) => a + b, 0.0),
    total_postmates: sales.map(s => s.postmates).reduce((a, b) => a + b, 0.0),
    total_snackpass: sales.map(s => s.snackpass).reduce((a, b) => a + b, 0.0),
    total_transactions: sales.map(s => Number(s.transactions)).reduce((a, b) => a + b, 0.0),
    total_expenses: expenses.map(e => e.amount).reduce((a, b) => a + b, 0.0),
    total_deposits: deposits.map(e => e.amount).reduce((a, b) => a + b, 0.0),
    total_deliveries: deliveries.map(e => e.amount).reduce((a, b) => a + b, 0.0),
    total_payrolls: gross_wages.map(p => p.gross_wages).reduce((a, b) => a + b, 0.0),
    daily_net_sales: sales.map(s => s.net_sales),
    daily_transactions: sales.map(s => s.transactions),
    payrolls: gross_wages.map(p => p.gross_wages)
  }
}

const getUserSummaryByMonth = async (user_id, from, to) => {
  const summary = []

  const unitIds = await models.unit_user.findAll({
    where: {
      user_id: user_id
    }
  }).map(u => u.unit_id)

  let currentMonth = moment(from).startOf('month')
  while (currentMonth <= to) {
    const currentMonthEnd = moment(currentMonth).endOf('month')
    const year = currentMonth.year()
    const month = currentMonth.month() + 1
    const saleIds = await models.sale.findAll({
      attributes: [
        'id',
      ],
      where: {
        [Op.and]: [
          {
            unit_id: unitIds
          },
          sequelize.where(sequelize.fn('YEAR', sequelize.col('sales_date')), year),
          sequelize.where(sequelize.fn('MONTH', sequelize.col('sales_date')), month),
        ]
      }
    }).map(s => s.id)

    const sales = await models.sale.findAll({
      attributes: [
        [sequelize.fn('sum', sequelize.col('net_sales')), 'net_sales'],
        [sequelize.fn('sum', sequelize.col('gross_sales')), 'gross_sales'],
        [sequelize.fn('sum', sequelize.col('tax')), 'tax'],
        [sequelize.fn('sum', sequelize.col('net_sales_uber_eats')), 'net_sales_uber_eats'],
        [sequelize.fn('sum', sequelize.col('tax_uber_eats')), 'tax_uber_eats'],
        [sequelize.fn('sum', sequelize.col('net_sales_postmates')), 'net_sales_postmates'],
        [sequelize.fn('sum', sequelize.col('tax_postmates')), 'tax_postmates'],
        [sequelize.fn('sum', sequelize.col('credit_sales')), 'credit_sales'],
        [sequelize.fn('sum', sequelize.col('amex_credit_sales')), 'amex_credit_sales'],
        [sequelize.fn('sum', sequelize.col('master_credit_sales')), 'master_credit_sales'],
        [sequelize.fn('sum', sequelize.col('discover_credit_sales')), 'discover_credit_sales'],
        [sequelize.fn('sum', sequelize.col('visa_credit_sales')), 'visa_credit_sales'],
        [sequelize.fn('sum', sequelize.col('debit_sales')), 'debit_sales'],
        [sequelize.fn('sum', sequelize.col('gift_card_redeem')), 'gift_card_redeem'],
        [sequelize.fn('sum', sequelize.col('gift_card_sold')), 'gift_card_sold'],
        [sequelize.fn('sum', sequelize.col('donations')), 'donations'],
        [sequelize.fn('sum', sequelize.col('cash')), 'cash'],
        [sequelize.fn('sum', sequelize.col('rbi_mobile_app')), 'rbi_mobile_app'],
        [sequelize.fn('sum', sequelize.col('uber_eats')), 'uber_eats'],
        [sequelize.fn('sum', sequelize.col('grubhub')), 'grubhub'],
        [sequelize.fn('sum', sequelize.col('doordash')), 'doordash'],
        [sequelize.fn('sum', sequelize.col('white_label')), 'white_label'],
        [sequelize.fn('sum', sequelize.col('postmates')), 'postmates'],
        [sequelize.fn('sum', sequelize.col('snackpass')), 'snackpass'],
        [sequelize.fn('sum', sequelize.col('transactions')), 'transactions'],
      ],
      where: {
        id: saleIds
      }
    })

    const expenses = await models.sales_expense.findAll({
      attributes: [
        [sequelize.fn('sum', sequelize.col('amount')), 'amount'],
      ],
      where: {
        [Op.and]: [
          {
            sale_id: saleIds
          }
        ]
      }
    })

    const deposits = await models.sales_deposit.findAll({
      attributes: [
        [sequelize.fn('sum', sequelize.col('amount')), 'amount'],
      ],
      where: {
        [Op.and]: [
          {
            sale_id: saleIds
          }
        ]
      }
    })

    const deliveries = await models.sales_food_delivery.findAll({
      attributes: [
        [sequelize.fn('sum', sequelize.col('amount')), 'amount'],
      ],
      where: {
        [Op.and]: [
          {
            sale_id: saleIds
          }
        ]
      }
    })

    const payrolls = await models.payroll.findAll({
      attributes: [
        'id',
        'period',
        'status',
        'unit_id',
        [sequelize.fn('STR_TO_DATE', sequelize.fn('SUBSTRING_INDEX', sequelize.col('period'), ">", -1), "%Y-%c-%d"), 'payroll_end']
      ],
      where: {
        unit_id: unitIds
      },
      having: {
        [Op.and]: [
          sequelize.where(sequelize.fn('YEAR', sequelize.col('payroll_end')), year),
          sequelize.where(sequelize.fn('MONTH', sequelize.col('payroll_end')), month),
        ]
      }
    })

    const gross_wages = await models.employee_payroll.findAll({
      attributes: [
        [sequelize.fn('sum', sequelize.col('gross_wages')), 'gross_wages'],
      ],
      where: {
        [Op.and]: [
          {
            payroll_id: payrolls.map(s => s.id)
          }
        ]
      }
    })

    summary.push({
      from: currentMonth,
      to: currentMonthEnd,
      total_stores: unitIds.length,
      total_net_sales: sales.map(s => s.net_sales).reduce((a, b) => a + b, 0.0),
      total_tax: sales.map(s => s.tax).reduce((a, b) => a + b, 0.0),
      total_gross_sales: sales.map(s => s.gross_sales).reduce((a, b) => a + b, 0.0),
      total_net_sales_uber_eats: sales.map(s => s.net_sales_uber_eats).reduce((a, b) => a + b, 0.0),
      total_tax_uber_eats: sales.map(s => s.tax_uber_eats).reduce((a, b) => a + b, 0.0),
      total_net_sales_postmates: sales.map(s => s.net_sales_postmates).reduce((a, b) => a + b, 0.0),
      total_tax_postmates: sales.map(s => s.tax_postmates).reduce((a, b) => a + b, 0.0),
      total_credit_sales: sales.map(s => s.credit_sales).reduce((a, b) => a + b, 0.0),
      total_amex_credit_sales: sales.map(s => s.amex_credit_sales).reduce((a, b) => a + b, 0.0),
      total_master_credit_sales: sales.map(s => s.master_credit_sales).reduce((a, b) => a + b, 0.0),
      total_discover_credit_sales: sales.map(s => s.discover_credit_sales).reduce((a, b) => a + b, 0.0),
      total_visa_credit_sales: sales.map(s => s.visa_credit_sales).reduce((a, b) => a + b, 0.0),
      total_debit_sales: sales.map(s => s.debit_sales).reduce((a, b) => a + b, 0.0),
      total_gift_card_redeem: sales.map(s => s.gift_card_redeem).reduce((a, b) => a + b, 0.0),
      total_gift_card_sold: sales.map(s => s.gift_card_sold).reduce((a, b) => a + b, 0.0),
      total_donations: sales.map(s => s.donations).reduce((a, b) => a + b, 0.0),
      total_cash: sales.map(s => s.cash).reduce((a, b) => a + b, 0.0),
      total_rbi_mobile_app: sales.map(s => s.rbi_mobile_app).reduce((a, b) => a + b, 0.0),
      total_uber_eats: sales.map(s => s.uber_eats).reduce((a, b) => a + b, 0.0),
      total_grubhub: sales.map(s => s.grubhub).reduce((a, b) => a + b, 0.0),
      total_doordash: sales.map(s => s.doordash).reduce((a, b) => a + b, 0.0),
      total_white_label: sales.map(s => s.white_label).reduce((a, b) => a + b, 0.0),
      total_postmates: sales.map(s => s.postmates).reduce((a, b) => a + b, 0.0),
      total_snackpass: sales.map(s => s.snackpass).reduce((a, b) => a + b, 0.0),
      total_transactions: sales.map(s => Number(s.transactions)).reduce((a, b) => a + b, 0.0),
      total_expenses: expenses.map(e => e.amount).reduce((a, b) => a + b, 0.0),
      total_deposits: deposits.map(e => e.amount).reduce((a, b) => a + b, 0.0),
      total_deliveries: deliveries.map(e => e.amount).reduce((a, b) => a + b, 0.0),
      total_payrolls: gross_wages.map(p => p.gross_wages).reduce((a, b) => a + b, 0.0),
      daily_net_sales: [],
      daily_transactions: [],
      payrolls: []
    })

    currentMonth = moment(currentMonth).add(1, 'month')
  }

  return summary
}

const saveReceivedRevenue = async (revenuereceiveInput, { auth }) => {
  console.log("Received Revenue Input:", revenuereceiveInput);

  try {
    const userId = auth?.userId || revenuereceiveInput.created_by;
    if (!userId) throw new Error('Unauthorized: Missing userId');

    const {
      unit_id,
      tenant_id,
      client_id,
      type,
      invoice_ids = [],
      amount,
      payment_mode,
      payment_date,
      send_email,
      print_receipt,
      card_number,
      barter_description,
      zelle_description,
      check_details,
    } = revenuereceiveInput;

    if (!type || !['tenant', 'client'].includes(type)) {
      throw new Error('Invalid type. Must be "tenant" or "client"');
    }
    if (!amount || isNaN(parseFloat(amount))) {
      throw new Error('Invalid or missing amount');
    }
    if (!payment_date) {
      throw new Error('Missing payment_date');
    }
    if (type === 'tenant' && !tenant_id) {
      throw new Error('Missing tenant_id for tenant type');
    }
    if (type === 'client' && !client_id) {
      throw new Error('Missing client_id for client type');
    }

    const finalInput = {
      unit_id,
      type,
      amount: parseFloat(amount),
      payment_mode,
      payment_date: payment_date
        ? new Date(payment_date).toISOString().split('T')[0]
        : new Date().toISOString().split('T')[0],
      send_email,
      print_receipt,
      card_number,
      barter_description,
      zelle_description,
      created_by: userId,
      created_at: new Date(),
      updated_at: new Date(),
    };

    if (payment_mode === 'Check' && check_details) {
      finalInput.cheque_number = check_details.number;
      finalInput.account_number = check_details.account;
      finalInput.routing_number = check_details.routing;
      finalInput.cheque_due_date = new Date(check_details.date);
    }

    let createdRevenue;

    if (type === 'tenant') {
      const { client_id, ...revenueData } = finalInput;


      createdRevenue = await models.revenue_received.create(revenueData);

      await models.tenant_revenue_received.create({
        tenant_id,
        revenue_id: createdRevenue.id,
        created_at: new Date(),
        updated_at: new Date(),
      });
    } else if (type === 'client') {

      const { tenant_id, ...revenueData } = finalInput;

      createdRevenue = await models.revenue_received.create(revenueData);

      await models.client_revenue_received.create({
        client_id,
        revenue_id: createdRevenue.id,
        created_at: new Date(),
        updated_at: new Date(),
      });
    }

    if (type === 'tenant') {

      const tenant = await models.tenants.findByPk(tenant_id);

      if (!tenant) throw new Error(`Tenant not found with ID: ${tenant_id}`);

      let remainingAmount = parseFloat(amount);
      let totalAppliedToInvoices = 0;

      let invoices = [];
      if (invoice_ids.length > 0) {
        console.log('Fetching invoices with IDs:', invoice_ids);
        invoices = await models.invoices.findAll({
          where: {
            id: { [Op.in]: invoice_ids },
            status: { [Op.in]: ['unpaid', 'partial'] },
          },
          order: [['id', 'ASC']],
        });
        if (invoices.length !== invoice_ids.length) {
          console.log('Some invoice IDs not found or invalid:', invoice_ids);
        }
      } else {
        console.log('Fetching all unpaid/partial invoices for tenant:', tenant_id);
        invoices = await models.invoices.findAll({
          include: [
            {
              model: models.tenant_invoices,
              as: 'tenant_invoices',
              where: { tenant_id },
              attributes: [],
            },
          ],
          where: {
            status: { [Op.in]: ['unpaid', 'partial'] },
          },
          order: [['issue_date', 'ASC'], ['id', 'ASC']],
        });
      }
      console.log('Found invoices:', invoices.map(i => i.id));

      for (const invoice of invoices) {
        const total = parseFloat(invoice.total || 0);
        const alreadyPaid = parseFloat(invoice.paid_amount || 0);
        if (isNaN(total) || isNaN(alreadyPaid)) {
          throw new Error(`Invalid invoice data for invoice #${invoice.id}: total=${total}, paid_amount=${alreadyPaid}`);
        }
        const balance = total - alreadyPaid;

        if (balance <= 0 || remainingAmount <= 0) continue;

        const applyAmount = Math.min(balance, remainingAmount);
        invoice.paid_amount = alreadyPaid + applyAmount;
        invoice.balance = total - invoice.paid_amount;
        invoice.status = invoice.balance <= 0 ? 'paid' : 'partial';
        invoice.updated_at = new Date();

        console.log(`Updating invoice #${invoice.id}:`, { applyAmount, newBalance: invoice.balance });
        await invoice.save();

        remainingAmount -= applyAmount;
        totalAppliedToInvoices += applyAmount;
      }

      const currentOpeningBalance = parseFloat(tenant.opening_balance || 0);
      if (isNaN(currentOpeningBalance)) {
        throw new Error(`Invalid tenant opening balance: ${tenant.opening_balance}`);
      }
      const newOpeningBalance = currentOpeningBalance - totalAppliedToInvoices - remainingAmount;

      console.log('Updating tenant balance:', { currentOpeningBalance, newOpeningBalance });
      await tenant.update({
        opening_balance: newOpeningBalance,
        updated_at: new Date(),
      });
    }
    else if (type === 'client') {

      const client = await models.client.findByPk(client_id);

      if (!client) throw new Error(`Client not found with ID: ${client_id}`);

      let remainingAmount = parseFloat(amount);
      let totalAppliedToInvoices = 0;

      let invoices = [];
      if (invoice_ids.length > 0) {
        console.log('Fetching invoices with IDs:', invoice_ids);
        invoices = await models.invoices.findAll({
          where: {
            id: { [Op.in]: invoice_ids },
            status: { [Op.in]: ['unpaid', 'partial'] },
          },
          order: [['id', 'ASC']],
        });
        if (invoices.length !== invoice_ids.length) {
          console.log('Some invoice IDs not found or invalid:', invoice_ids);
        }
      } else {
        console.log('Fetching all unpaid/partial invoices for tenant:', client_id);
        invoices = await models.invoices.findAll({
          include: [
            {
              model: models.client_invoices,
              as: 'client_invoices',
              where: { client_id },
              attributes: [],
            },
          ],
          where: {
            status: { [Op.in]: ['unpaid', 'partial'] },
          },
          order: [['issue_date', 'ASC'], ['id', 'ASC']],
        });
      }
      console.log('Found invoices:', invoices.map(i => i.id));

      for (const invoice of invoices) {
        const total = parseFloat(invoice.total || 0);
        const alreadyPaid = parseFloat(invoice.paid_amount || 0);
        if (isNaN(total) || isNaN(alreadyPaid)) {
          throw new Error(`Invalid invoice data for invoice #${invoice.id}: total=${total}, paid_amount=${alreadyPaid}`);
        }
        const balance = total - alreadyPaid;

        if (balance <= 0 || remainingAmount <= 0) continue;

        const applyAmount = Math.min(balance, remainingAmount);
        invoice.paid_amount = alreadyPaid + applyAmount;
        invoice.balance = total - invoice.paid_amount;
        invoice.status = invoice.balance <= 0 ? 'paid' : 'partial';
        invoice.updated_at = new Date();

        console.log(`Updating invoice #${invoice.id}:`, { applyAmount, newBalance: invoice.balance });
        await invoice.save();

        remainingAmount -= applyAmount;
        totalAppliedToInvoices += applyAmount;
      }

      const currentOpeningBalance = parseFloat(client.opening_balance || 0);
      if (isNaN(currentOpeningBalance)) {
        throw new Error(`Invalid client opening balance: ${client.opening_balance}`);
      }
      const newOpeningBalance = currentOpeningBalance - totalAppliedToInvoices - remainingAmount;

      console.log('Updating client balance:', { currentOpeningBalance, newOpeningBalance });
      await client.update({
        opening_balance: newOpeningBalance,
        updated_at: new Date(),
      });
    }

    return {
      id: createdRevenue.id,
      amount: createdRevenue.amount,
      status: 'saved',
      payment_mode: createdRevenue.payment_mode,
      payment_date: payment_date,
    };
  } catch (error) {
    console.error('Error saving revenue:', {
      message: error.message,
      stack: error.stack,
      revenuereceiveInput,
      userId: auth?.userId,
    });
    throw new Error(`Failed to save revenue record: ${error.message}`);
  }
};

const bankentry = async (bankInput, { auth }) => {
  console.log('bank Input resolver', bankInput);

  const user = await models.user.findOne({ where: { id: auth.userId } });
  if (!user) return false;

  const data = {
    name: bankInput.name,
    account_name: bankInput.account_name,
    account_no: bankInput.account_no,
    routing_no: bankInput.routing_no,
    check_no: bankInput.check_no,
    opening_balance: bankInput.opening_balance || 0,
    description: bankInput.description,
    street_no: bankInput.street_no,
    city: bankInput.city,
    state: bankInput.state,
    zip_code: bankInput.zip_code,
    status: bankInput.status || 'Active'
  };

  if (bankInput.id) {
    await models.NewBank.update(data, { where: { id: bankInput.id } });
  } else {
    const newBank = await models.NewBank.create({
      ...data,
      unit_id: bankInput.unit_id,
      created_at: new Date(),
      updated_at: new Date()
    });

    // if (bankInput.unit_id) {
    //   await models.unit_bank.create({
    //     bank_id: newBank.id,
    //     unit_id: bankInput.unit_id,
    //     created_at: new Date(),
    //     updated_at: new Date()
    //   });
    // }
  }

  return true;
};

const savePropertyEntry = async (propertyInput, { auth }) => {
  console.log(propertyInput, "property Input");

  const { id, property_items, property_taxes, ...input } = propertyInput;

  try {
    if (!models || !models.property || !models.property_item || !models.property_tax) {
      throw new Error('Required models not found (check your models)');
    }

    const userId = auth?.userId || propertyInput.created_by;
    if (!userId) throw new Error('Unauthorized user');

    const transaction = await models.sequelize.transaction();

    try {
      const property = await models.property.create(
        {
          ...input,
          created_by: userId,
          created_at: new Date(),
          updated_at: new Date(),
        },
        { transaction }
      );

      const propertyId = property.id;

      // 2. Save property taxes if any
      if (property_taxes && property_taxes.length > 0) {
        for (const tax of property_taxes) {
          await models.property_tax.create(
            {
              ...tax,
              property_id: propertyId,
              created_at: new Date(),
              updated_at: new Date(),
            },
            { transaction }
          );
        }
      }

      // 3. Save property items if any
      if (property_items && property_items.length > 0) {
        for (const item of property_items) {
          await models.property_item.create(
            {
              ...item,
              property_id: propertyId,
              created_at: new Date(),
              updated_at: new Date(),
            },
            { transaction }
          );
        }
      }

      // Commit transaction
      await transaction.commit();
      return propertyId;
    } catch (err) {
      await transaction.rollback();
      console.error('Transaction failed:', err.message);
      return false;
    }
  } catch (error) {
    console.error('Error in save Property Entry:', error.message);
    return false;
  }
};



const updatePropertyEntry = async (propertyupdateInput, { auth }) => {
  const { id, ...rest } = propertyupdateInput
  const property = await models.property.findByPk(id)
  if (!property) throw new Error('Property not found')
  await property.update(rest)
  return property.id
};

const updateTenantEntry = async (tenantUpdateInput, { auth }) => {
  const { id, email, ...rest } = tenantUpdateInput;

  const tenant = await models.tenants.findByPk(id);
  if (!tenant) throw new Error('Tenant not found');

  if (email && email !== tenant.email) {
    const emailExists = await models.tenants.findOne({
      where: {
        email,
        id: { [models.Sequelize.Op.ne]: id } // Exclude current tenant ID
      }
    });

    if (emailExists) {
      throw new Error('This email already exists');
    }
  }

  await tenant.update({
    ...rest,
    email, // include updated email
    updated_at: new Date(),
  });

  return tenant.id;
};

const updateOwnerEntry = async (ownerUpdateInput, { auth }) => {

  console.log(ownerUpdateInput, "owner update ownerUpdateInput")
  const { id, email, ...input } = ownerUpdateInput;

  try {
    if (!id) throw new Error('Owner ID is required for update');

    const property_owner = await models.owner.findByPk(id);
    if (!property_owner) throw new Error('Owner not found');

    const userId = auth?.userId || input.updated_by || null;
    if (!userId) throw new Error('Unauthorized user');

    // Check if email is being updated to another that already exists
    if (email) {
      const emailExists = await models.owner.findOne({
        where: {
          email,
          id: { [models.Sequelize.Op.ne]: id } // exclude current record
        }
      });

      if (emailExists) {
        throw new Error('This email already exists');
      }
    }

    const finalInput = {
      ...input,
      ...(email ? { email } : {}),
      updated_at: new Date(),
      updated_by: userId
    };

    console.log(finalInput, "owner update finalInput")

    await property_owner.update(finalInput);
    return property_owner.id;

  } catch (error) {
    console.error('Error updating Owner:', error.message);
    throw new Error(error.message);
  }
};

const updateBankEntry = async (bankUpdateInput, { auth }) => {
  console.log(bankUpdateInput, "bank update bankUpdateInput");
  const { id, ...input } = bankUpdateInput;

  try {
    if (!id) throw new Error('Bank ID is required for update');

    const bank = await models.NewBank.findByPk(id);
    if (!bank) throw new Error('Bank not found');

    const userId = auth?.userId || input.updated_by || null;
    if (!userId) throw new Error('Unauthorized user');

    const finalInput = {
      ...input,
      updated_at: new Date(),
      updated_by: userId
    };

    console.log(finalInput, "bank update finalInput");

    await bank.update(finalInput);
    return bank.id;

  } catch (error) {
    console.error('Error updating Bank:', error.message);
    throw new Error(error.message);
  }
};

const updatePropertyItemEntry = async (propertyItemUpdateInput, { auth }) => {
  const { id, ...rest } = propertyItemUpdateInput
  const property_item = await models.property_item.findByPk(id)
  if (!property_item) throw new Error('Property Item not found')
  await property_item.update(rest)
  return property_item.id
};

const updatePropertyTex = async (propertyTaxUpdateInput, { auth }) => {
  const { id, ...rest } = propertyTaxUpdateInput
  const property_tex = await models.property_tax.findByPk(id)
  if (!property_tex) throw new Error('Property Item not found')
  await property_tex.update(rest)
  return property_tex.id
};

const updateEmployeeShift = async (employeeShiftInput, { auth }) => {
  const { id, ...rest } = employeeShiftInput
  const employeeShift = await models.employee_shift.findByPk(id)
  if (!employeeShift) throw new Error('Property Item not found')
  await employeeShift.update(rest)
  return employeeShift.id
};

const setEmployeeShiftDefault = async (id, { auth }) => {
  const employeeShift = await models.employee_shift.findByPk(id);
  if (!employeeShift) throw new Error('Shift not found');

  // Set all other shifts to is_default = false
  await models.employee_shift.update({ is_default: false }, { where: {} });

  // Set selected shift to is_default = true
  await employeeShift.update({ is_default: true });

  return employeeShift.id;
};

const updateTenantContactsEntry = async (contactsUpdateInput, { auth }) => {
  const { id, email, ...rest } = contactsUpdateInput;
  const tenantContact = await models.tenant_contacts.findByPk(id);
  console.log(tenantContact, "tenantContact");
  if (!tenantContact) {
    throw new Error('Tenant Contact not found');
  }
  if (email && email !== tenantContact.email) {
    const emailExists = await models.tenant_contacts.findOne({
      where: {
        email,
        id: { [models.Sequelize.Op.ne]: id }, // exclude current contact
      },
    });
    if (emailExists) {
      throw new Error('This email already exists');
    }
  }
  await tenantContact.update({
    ...rest,
    email,
    updated_at: new Date(),
  });
  return tenantContact.id;
};



const updateTenantOccupancyEntry = async (occupancyUpdateInput, { auth }) => {
  const { id, items, ...rest } = occupancyUpdateInput;

  const tenant_occupancy = await models.agreement.findByPk(id);
  if (!tenant_occupancy) throw new Error('Tenant Occupancy not found');

  await tenant_occupancy.update(rest);

  if (Array.isArray(items)) {
    // Delete old items and recreate (simpler than diffing)
    await models.agreement_items.destroy({ where: { agreement_id: id } });

    const newItems = items.map(item => ({
      ...item,
      agreement_id: id,
    }));
    await models.agreement_items.bulkCreate(newItems);
  }

  return tenant_occupancy;
};


const savePropertyItemEntry = async (propertyItemInput, { auth }) => {
  console.log(propertyItemInput, "propertyItemInput");

  try {
    if (!models || !models.property_item) {
      throw new Error('Model "property_item" is missing');
    }

    const userId = auth?.userId || propertyItemInput.user_id;
    if (!userId) throw new Error('Unauthorized user');

    const finalInput = {
      ...propertyItemInput,
      created_at: new Date(),
      updated_at: new Date(),
    };

    const created = await models.property_item.create(finalInput);
    console.log("Created item record:", created.toJSON());

    return true;
  } catch (error) {
    console.error('Error in savePropertyItemEntry:', error.message);
    return false;
  }
};

const savePropertyTaxEntry = async (propertyTaxInput, { auth }) => {
  console.log(propertyTaxInput, "propertyTaxInput");

  try {
    if (!models || !models.property_tax) {
      throw new Error('Model "property_tax" is missing');
    }

    const userId = auth?.userId || propertyTaxInput.user_id;
    if (!userId) throw new Error('Unauthorized user');

    const finalInput = {
      ...propertyTaxInput,
      created_at: new Date(),
      updated_at: new Date(),
    };

    const created = await models.property_tax.create(finalInput);
    console.log("Created tax record:", created.toJSON());

    return true;
  } catch (error) {
    console.error('Error in savePropertyTaxEntry:', error.message);
    return false;
  }
};

const savePropertyDocsEntry = async (propertyDocInput, { auth }) => {
  try {
    if (!models || !models.document) {
      throw new Error('Model "property_tax" is missing');
    }

    const userId = auth?.userId || propertyDocInput.user_id;
    if (!userId) throw new Error('Unauthorized user');

    const finalInput = {
      ...propertyDocInput,
      created_at: new Date(),
      updated_at: new Date(),
    };

    const created = await models.document.create(finalInput);

    return true;
  } catch (error) {
    console.error('Error in savePropertyDocsEntry:', error.message);
    return false;
  }
};

const deleteProperty = async (id) => {
  console.log(id, "deleteProperty");

  try {
    // Optionally check if property exists
    const property = await models.property.findByPk(id)
    if (!property) return false

    // You can use `destroy` if you want to hard delete
    await models.property.destroy({
      where: { id }
    })

    return true
  } catch (error) {
    console.error('Error deleting property:', error)
    return false
  }
};

const deleteEmployeeShift = async (id) => {
  console.log(id, "deleteshift");

  try {
    // Optionally check if property exists
    const shift = await models.employee_shift.findByPk(id)
    if (!shift) return false

    // You can use `destroy` if you want to hard delete
    await models.employee_shift.destroy({
      where: { id }
    })

    return true
  } catch (error) {
    console.error('Error deleting shift:', error)
    return false
  }
};

const deleteChartAccount = async (id) => {
  console.log(id, "deleteChartAccount");

  try {
    const chartAccount = await models.chart_of_account.findByPk(id)
    if (!chartAccount) return false

    await models.chart_of_account.destroy({
      where: { id }
    })

    return true
  } catch (error) {
    console.error('Error deleting chart account:', error)
    return false
  }
};

const deleteConsent = async (id) => {
  console.log(id, "delete Consent");

  try {
    const chartAccount = await models.signConsentDocs.findByPk(id)
    if (!chartAccount) return false

    await models.signConsentDocs.destroy({
      where: { id }
    })

    return true
  } catch (error) {
    console.error('Error delete Consent', error)
    return false
  }
};

const deleteTenant = async (id) => {
  console.log(id, "deleteProperty");

  try {
    // Optionally check if property exists
    const tenant = await models.tenants.findByPk(id)
    if (!tenant) return false

    // You can use `destroy` if you want to hard delete
    await models.tenants.destroy({
      where: { id }
    })

    return true
  } catch (error) {
    console.error('Error deleting tenant:', error)
    return false
  }
};

const deleteInvoice = async (id, type) => {
  const t = await models.sequelize.transaction();

  console.log('delete Invoice', id, type);

  try {
    const invoice = await models.invoices.findByPk(id, { transaction: t });
    if (!invoice) {
      await t.rollback();
      return false;
    }

    let parentId, parentModel, assocTable;

    if (type === 'tenant') {
      assocTable = models.tenant_invoices;
      parentModel = models.tenants;
    } else if (type === 'client') {
      assocTable = models.client_invoices;
      parentModel = models.client;
    } else {
      await t.rollback();
      throw new Error('Invalid type. Must be "tenant" or "client".');
    }

    const junction = await assocTable.findOne({
      where: { invoice_id: invoice.id },
      attributes: ['tenant_id', 'client_id'].filter(col => col.includes(type)),
      transaction: t,
    });

    if (!junction) {
      await t.rollback();
      throw new Error(`${type} association not found for this invoice`);
    }

    parentId = junction.dataValues[`${type}_id`];

    const parent = await parentModel.findByPk(parentId, { transaction: t });
    if (!parent) {
      await t.rollback();
      throw new Error(`${type} not found`);
    }

    const newBalance =
      Number(parent.opening_balance || 0) - Number(invoice.total || 0);

    await parent.update(
      {
        opening_balance: newBalance,
        updated_at: new Date(),
      },
      { transaction: t }
    );

    await invoice.destroy({ transaction: t });

    await t.commit();
    return true;
  } catch (error) {
    await t.rollback();
    console.error('Error deleting invoice and adjusting balance:', error);
    return false;
  }
};

const deleteRecurringInvoice = async (id) => {
  try {
    const invoice = await models.recurring_invoices.findByPk(id, {
      include: ['items'],
    });

    if (!invoice) return false;

    if (invoice.items && invoice.items.length) {
      for (const item of invoice.items) {
        await item.destroy();
      }
    }

    await invoice.destroy();
    return true;

  } catch (error) {
    console.error('Error deleting invoice and its items:', error);
    return false;
  }
};

const deleteHoliday = async (id) => {
  try {
    const holiday = await models.holiday.findByPk(id);
    if (!holiday) {
      console.log('No holiday found with ID:', id)
      return false
    }

    await holiday.destroy({
      where: { id }
    })

    return true
  } catch (error) {
    console.error('Error deleting Tenant Occupancy:', error)
    return false
  }
}
const deleteleave = async (id) => {
  try {
    const leave = await models.leave.findByPk(id);
    if (!leave) {
      console.log('No leave found with ID:', id)
      return false
    }

    await leave.destroy({
      where: { id }
    })

    return true
  } catch (error) {
    console.error('Error deleting leave :', error)
    return false
  }
}

const deleteleaveapp = async (id) => {
  try {
    const leave = await models.leave.findByPk(id);

    if (!leave) {
      return {
        success: false,
        message: `No leave found with ID: ${id}`,
      };
    }

    await leave.destroy(); // No need for `where` when using instance method

    return {
      success: true,
      message: 'Leave application deleted successfully',
    };
  } catch (error) {
    console.error('Error deleting leave:', error);
    return {
      success: false,
      message: 'Failed to delete leave application',
    };
  }
};



const deleteDepartment = async (id) => {
  try {
    const department = await models.department.findByPk(id);
    if (!department) {
      console.log('No department found with ID:', id)
      return false
    }

    await department.destroy({
      where: { id }
    })

    return true
  } catch (error) {
    console.error('Error deleting department :', error)
    return false
  }
}

const deleteDesignations = async (id) => {
  try {
    const designation = await models.designation.findByPk(id);
    if (!designation) {
      console.log('No designation found with ID:', id)
      return false
    }

    await designation.destroy({
      where: { id }
    })

    return true
  } catch (error) {
    console.error('Error deleting designation :', error)
    return false
  }
}




const deleteOwner = async (id) => {
  try {
    // Optionally check if property exists
    const Owner = await models.owner.findByPk(id)
    if (!Owner) return false

    // You can use `destroy` if you want to hard delete
    await models.owner.destroy({
      where: { id }
    })

    return true
  } catch (error) {
    console.error('Error deleting Owner:', error)
    return false
  }
};

const deleteproject = async (id) => {
  try {
    const Project = await models.projects.findByPk(id)
    if (!Project) return false
    await models.projects.destroy({
      where: { id }
    })
    return true
  } catch (error) {
    console.error('Error deleting projects:', error)
    return false
  }
};



const deletetask = async (id) => {
  const t = await models.sequelize.transaction();
  try {
    const task = await models.tasks.findByPk(id, { transaction: t });
    if (!task) return false;

    // Delete related records
    await models.task_employee.destroy({ where: { task_id: id }, transaction: t });
    await models.task_notes.destroy({ where: { task_id: id }, transaction: t });
    await models.task_comments.destroy({ where: { task_id: id }, transaction: t });
    await models.task_history.destroy({ where: { task_id: id }, transaction: t });
    await models.sub_tasks.destroy({ where: { task_id: id }, transaction: t });
    await models.project_time_logs.destroy({ where: { task_id: id }, transaction: t });

    await task.destroy({ transaction: t });

    await t.commit();
    return true;
  } catch (error) {
    await t.rollback();
    console.error('Error deleting task:', error);
    return false;
  }
};

const deleteSubtask = async (id) => {
  try {
    const subtask = await models.sub_tasks.findByPk(id);
    if (!subtask) {
      console.warn(`Client with id ${id} not found`);
      return false;
    }

    await models.sub_tasks.destroy({ where: { id } });
    return true;
  } catch (error) {
    console.error("Error deleting sub task:", error);
    return false;
  }
};


const deleteClient = async (id) => {
  try {

    if (!id) {
      console.warn("deleteClient called without an ID");
      return false;
    }


    if (!models || !models.client) {
      console.error("Client model not found in Sequelize models");
      return false;
    }


    const client = await models.client.findByPk(id);
    if (!client) {
      console.warn(`Client with id ${id} not found`);
      return false;
    }


    await models.client.destroy({ where: { id } });
    return true;
  } catch (error) {
    console.error("Error deleting client:", error);
    return false;
  }
};

const deleteClientService = async (id) => {
  try {

    if (!id) {
      console.warn("deleteClientService called without an ID");
      return false;
    }

    if (!models || !models.client_service) {
      console.error("Client Service model not found in Sequelize models");
      return false;
    }


    const client_service = await models.client_service.findByPk(id);
    if (!client_service) {
      console.warn(`Client Service with id ${id} not found`);
      return false;
    }


    await models.client_service.destroy({ where: { id } });
    return true;
  } catch (error) {
    console.error("Error deleting client service:", error);
    return false;
  }
};

const deleteClientEntity = async (id) => {
  try {
    // ✅ Check for valid ID
    if (!id) {
      console.warn("deleteClientEntity called without an ID");
      return false;
    }

    // ✅ Ensure model exists
    if (!models || !models.client_entity) {
      console.error("Client Entity model not found in Sequelize models");
      return false;
    }

    // ✅ Check if client exists first
    const client_entity = await models.client_entity.findByPk(id);
    if (!client_entity) {
      console.warn(`Client Entity with id ${id} not found`);
      return false;
    }

    // ✅ Delete if found
    await models.client_entity.destroy({ where: { id } });
    return true;
  } catch (error) {
    console.error("Error deleting client entity:", error);
    return false;
  }
};



const deletePropertyDocs = async (id) => {
  console.log(id, "deletePropertyDocs");

  try {
    // Optionally check if property exists
    const propertydocs = await models.document.findByPk(id)
    if (!propertydocs) return false

    // You can use `destroy` if you want to hard delete
    await models.document.destroy({
      where: { id }
    })

    return true
  } catch (error) {
    console.error('Error deleting property Docs:', error)
    return false
  }
};

const deletePropertyTaxes = async (id) => {
  console.log(id, "deletePropertyTaxes");

  try {
    // Optionally check if property exists
    const property_tax = await models.property_tax.findByPk(id)
    if (!property_tax) return false

    // You can use `destroy` if you want to hard delete
    await models.property_tax.destroy({
      where: { id }
    })

    return true
  } catch (error) {
    console.error('Error deleting property Docs:', error)
    return false
  }
};

const deleteTenantContacts = async (id) => {
  try {
    // Optionally check if property exists
    const tenant_contacts = await models.tenant_contacts.findByPk(id)
    if (!tenant_contacts) return false

    // You can use `destroy` if you want to hard delete
    await models.tenant_contacts.destroy({
      where: { id }
    })

    return true
  } catch (error) {
    console.error('Error deleting Tenant Contacts:', error)
    return false
  }
};

const deleteGlobalCurrency = async (id, { auth }) => {
  try {
    if (!models?.global_currency) {
      throw new Error('global_currency model not found');
    }

    const userId = auth?.userId;
    if (!userId) throw new Error('Unauthorized user');

    const existingCurrency = await models.global_currency.findByPk(id);
    if (!existingCurrency) {
      throw new Error(`Currency with ID ${id} not found`);
    }

    await models.global_currency.destroy({
      where: { id }
    });

    return true;
  } catch (error) {
    console.error('Error deleting GlobalCurrency:', error.message);
    throw new Error(error.message);
  }
};

const deletepackage = async (id, { auth }) => {
  try {
    if (!models?.package) {
      throw new Error(' Package model not found');
    }

    const userId = auth?.userId;
    if (!userId) throw new Error('Unauthorized user');

    const existingPackage = await models.package.findByPk(id);
    if (!existingPackage) {
      throw new Error(`existing Package with ID ${id} not found`);
    }

    await models.package.destroy({
      where: { id }
    });
    return true;
  } catch (error) {
    console.error('Error deleting  Package:', error.message);
    throw new Error(error.message);
  }
};

const deletevendor = async (id, { auth }) => {
  try {
    if (!models?.vendor) {
      throw new Error(' vendor model not found');
    }

    const userId = auth?.userId;
    if (!userId) throw new Error('Unauthorized user');

    const existingPackage = await models.vendor.findByPk(id);
    if (!existingPackage) {
      throw new Error(`existing vendor with ID ${id} not found`);
    }

    await models.vendor.destroy({
      where: { id }
    });
    return true;
  } catch (error) {
    console.error('Error deleting  vendor:', error.message);
    throw new Error(error.message);
  }
};

const deletebank = async (id, { auth }) => {
  try {
    if (!models?.NewBank) {
      throw new Error('Vendor type model not found');
    }

    const userId = auth?.userId;
    if (!userId) throw new Error('Unauthorized user');

    const existingVendorType = await models.NewBank.findByPk(id);
    if (!existingVendorType) {
      throw new Error(`Vendor type with ID ${id} not found`);
    }

    await existingVendorType.destroy();
    return true;
  } catch (error) {
    console.error('Error deleting vendor type:', error);
    throw new Error(`Failed to delete vendor type: ${error.message}`);
  }
};

const deleteTemoraryEmployee = async (id, { auth }) => {
  try {
    if (!models?.temporary_employee) {
      throw new Error(' Package model not found');
    }

    const userId = auth?.userId;
    if (!userId) throw new Error('Unauthorized user');

    const existingTemporaryEmployee = await models.temporary_employee.findByPk(id);
    if (!existingTemporaryEmployee) {
      throw new Error(`existing Temporary Employee with ID ${id} not found`);
    }

    await models.temporary_employee.destroy({
      where: { id }
    });

    return true;
  } catch (error) {
    console.error('Error deleting Temporary Employee:', error.message);
    throw new Error(error.message);
  }
};

const deleteVendorType = async (id, { auth }) => {
  try {
    if (!models?.vendor_type) {
      throw new Error('Vendor type model not found');
    }

    const userId = auth?.userId;
    if (!userId) throw new Error('Unauthorized user');

    const existingVendorType = await models.vendor_type.findByPk(id);
    if (!existingVendorType) {
      throw new Error(`Vendor type with ID ${id} not found`);
    }

    await existingVendorType.destroy(); // ✅ directly destroy instance
    return true;
  } catch (error) {
    console.error('Error deleting vendor type:', error);
    throw new Error(`Failed to delete vendor type: ${error.message}`);
  }
};



const deleteCheck = async (id, { auth }) => {
  try {
    if (!models?.checks || !models?.check_items) {
      throw new Error("Checks or CheckItems model not found");
    }

    const userId = auth?.userId;
    if (!userId) throw new Error("Unauthorized user");

    const existingCheck = await models.checks.findByPk(id, {
      include: [{ model: models.check_items, as: "items" }],
    });

    if (!existingCheck) {
      throw new Error(`Check with ID ${id} not found`);
    }

    await models.check_items.destroy({
      where: { check_id: id },
    });

    await existingCheck.destroy();

    return true;
  } catch (error) {
    console.error("Error deleting check:", error.message);
    throw new Error(`Failed to delete check: ${error.message}`);
  }
};

const deleteinvitation = async (id) => {
  try {
    const invitation = await models.invitation.findByPk(id)

    if (!invitation) return false

    await models.invitation.destroy({
      where: { id }
    })

    return true
  } catch (error) {
    console.error('Error deleting invitation item:', error)
    return false
  }
};

const deleteExpenseType = async (id, { auth }) => {
  try {
    if (!models.ExpenseType) {
      throw new Error('expense type model not found');
    }

    const userId = auth?.userId;
    if (!userId) throw new Error('Unauthorized user');

    const existingVendorType = await models.ExpenseType.findByPk(id);
    if (!existingVendorType) {
      throw new Error(`expense Type with ID ${id} not found`);
    }

    await existingVendorType.destroy();
    return true;
  } catch (error) {
    console.error('Error deleting expense type:', error);
    throw new Error(`Failed to delete expense type: ${error.message}`);
  }
};

const deleteExpense = async (id, { auth }) => {
  try {
    if (!models.expenses) {
      throw new Error('expense model not found');
    }

    const userId = auth?.userId;
    if (!userId) throw new Error('Unauthorized user');

    const existingexpenses = await models.expenses.findByPk(id);
    if (!existingexpenses) {
      throw new Error(`expense Type with ID ${id} not found`);
    }

    await existingexpenses.destroy();
    return true;
  } catch (error) {
    console.error('Error deleting expense:', error);
    throw new Error(`Failed to delete expense: ${error.message}`);
  }
};


const deleteTenantOccupancy = async (id) => {
  try {
    // 1. Check if the agreement exists
    const tenant_occupancy = await models.agreement.findByPk(id)
    if (!tenant_occupancy) {
      console.log('No tenant_occupancy found with ID:', id)
      return false
    }

    // 2. Delete all related agreement_items
    await models.agreement_items.destroy({
      where: { agreement_id: id }
    })

    // 3. Delete the agreement itself
    await models.agreement.destroy({
      where: { id }
    })

    return true
  } catch (error) {
    console.error('Error deleting Tenant Occupancy:', error)
    return false
  }
}

const deletePropertyItems = async (id) => {
  try {
    // Optionally check if property exists
    const property_item = await models.property_item.findByPk(id)
    if (!property_item) return false

    // You can use `destroy` if you want to hard delete
    await models.property_item.destroy({
      where: { id }
    })

    return true
  } catch (error) {
    console.error('Error deleting property Items:', error)
    return false
  }
};

const deletepropertytaxes = async (id) => {
  try {
    const property_tax = await models.property_tax.findByPk(id)
    if (!property_tax) return false

    await models.property_tax.destroy({
      where: { id }
    })

    return true
  } catch (error) {
    console.error('Error deleting property Items:', error)
    return false
  }
};

const saveTenantEntry = async (tenantInput, { auth }) => {
  try {
    if (!models || !models.tenants || !models.tenant_contacts) {
      throw new Error('Tenant or contact model not found');
    }

    console.log('resolver tenant input', tenantInput);

    const userId = auth?.userId;
    if (!userId) throw new Error('Unauthorized user');

    const { id, email, contacts = [], ...input } = tenantInput;
    const finalInput = {
      ...input,
      email,
      created_by: userId,
      created_at: new Date(),
      updated_at: new Date(),
    };

    let tenantId;

    if (id && id > 0) {
      // UPDATE CASE
      const existing = await models.tenants.findByPk(id);
      if (!existing) throw new Error('Tenant not found');

      if (email && email !== existing.email) {
        const emailExists = await models.tenants.findOne({
          where: {
            email,
            id: { [models.Sequelize.Op.ne]: id }
          }
        });
        if (emailExists) throw new Error('This email already exists');
      }

      await models.tenants.update(finalInput, { where: { id } });
      tenantId = id;

      // Clear old contacts before adding new ones
      await models.tenant_contacts.destroy({ where: { tenant_id: tenantId } });
    } else {
      // CREATE CASE
      const emailExists = await models.tenants.findOne({ where: { email } });
      if (emailExists) throw new Error('This email already exists');

      const created = await models.tenants.create(finalInput);
      tenantId = created.id;
    }

    // Save Contacts if any
    if (contacts.length > 0) {
      const contactPayload = contacts.map(c => ({
        tenant_id: tenantId,
        type: c.type || null,
        name: c.name || null,
        is_name_show: c.is_name_show ?? false,
        first_name: c.first_name || null,
        last_name: c.last_name || null,
        ssn: c.ssn || null,
        phone: c.phone || null,
        email: c.email || null,
        id_type: c.id_type || null,
        id_number: c.id_number || null,
        gender: c.gender || null,
        date_of_birth: c.date_of_birth || null,
        monthly_gross_income: c.monthly_gross_income ? Number(c.monthly_gross_income) : null,
        additional_income: c.additional_income ? Number(c.additional_income) : null,
        marital_status: c.marital_status || null,
        ethnicity: c.ethnicity || null,
        created_at: new Date(),
        updated_at: new Date()
      }));

      await models.tenant_contacts.bulkCreate(contactPayload);
    }
    console.log('tenant Id in resolver', tenantId)
    return tenantId;
  } catch (error) {
    console.error('Error in save Tenant Entry:', error.message);
    throw new Error(error.message);
  }
};

const saveInvoiceEntry = async (invoiceInput, { auth }) => {
  try {
    // === Validate Models ===
    if (
      !models?.invoices ||
      !models?.invoice_items ||
      !models?.tenants ||
      !models?.client ||
      !models?.tenant_invoices ||
      !models?.client_invoices ||
      !models?.unit
    ) {
      throw new Error('Required models not found in context');
    }

    const userId = auth?.userId || invoiceInput.created_by;
    if (!userId) throw new Error('Unauthorized');

    const {
      id,
      items = [],
      total = 0,
      tenant_id,
      client_id,
      type,
      ...mainData
    } = invoiceInput;

    // === Required Fields ===
    const requiredFields = ['unit_id', 'invoice_no', 'issue_date', 'due_date', 'subtotal'];
    for (const field of requiredFields) {
      if (!mainData[field] && mainData[field] !== 0) {
        throw new Error(`Missing required field: ${field}`);
      }
    }

    if (!type || !['tenant', 'client'].includes(type)) {
      throw new Error('Invalid or missing invoice type');
    }
    if (type === 'tenant' && !tenant_id) {
      throw new Error('Missing tenant_id for tenant invoice');
    }
    if (type === 'client' && !client_id) {
      throw new Error('Missing client_id for client invoice');
    }

    // === Validate Unit ===
    const unit = await models.unit.findByPk(mainData.unit_id);
    if (!unit) throw new Error(`Unit not found with ID: ${mainData.unit_id}`);

    // === Check Duplicate Invoice No (on create) ===
    if (!id && mainData.invoice_no) {
      const existingInvoice = await models.invoices.findOne({
        where: { invoice_no: mainData.invoice_no, unit_id: mainData.unit_id }
      });
      if (existingInvoice) {
        throw new Error(`Invoice number ${mainData.invoice_no} already exists for this unit`);
      }
    }

    // === Fetch Entity (Tenant or Client) ===
    let entity;
    if (type === 'tenant') {
      entity = await models.tenants.findByPk(tenant_id);
      if (!entity) throw new Error(`Tenant not found with ID: ${tenant_id}`);
    } else {
      entity = await models.client.findByPk(client_id);
      if (!entity) throw new Error(`Client not found with ID: ${client_id}`);
    }

    // === Balance Logic ===
    const openingBalance = Number(entity.opening_balance || 0);
    const invoiceTotal = Number(total);
    if (isNaN(invoiceTotal) || invoiceTotal < 0) {
      throw new Error('Invalid total value');
    }

    let appliedAmount = 0;
    if (openingBalance < 0) {
      appliedAmount = Math.min(invoiceTotal, Math.abs(openingBalance));
    }

    const invoiceBalance = invoiceTotal - appliedAmount;
    const invoiceStatus = invoiceBalance === 0 ? 'paid' : appliedAmount > 0 ? 'partial' : 'unpaid';
    const newOpeningBalance = openingBalance + invoiceTotal;

    // === Final Invoice Data ===
    const finalData = {
      ...mainData,
      unit_id: mainData.unit_id,
      receipent_email: mainData.receipent_email,
      invoice_no: mainData.invoice_no,
      issue_date: new Date(mainData.issue_date),
      due_date: new Date(mainData.due_date),
      note: mainData.note || null,
      subtotal: Number(mainData.subtotal),
      discount_type: mainData.discount_type || null,
      discount: Number(mainData.discount) || 0,
      tenant_id: type === 'tenant' ? tenant_id : null,
      client_id: type === 'client' ? client_id : null,
      type,
      total: invoiceTotal,
      balance: invoiceBalance,
      paid_amount: appliedAmount,
      status: invoiceStatus,
      send_email: mainData.send_email || 'false',
      print_invoice: mainData.print_invoice || 'false',
      print_fax: mainData.print_fax || 'false',
      created_by: userId,
      created_at: id ? undefined : new Date(),
      updated_at: new Date(),
    };

    // === Save Invoice ===
    let invoiceId;
    if (id && id > 0) {
      const existing = await models.invoices.findByPk(id);
      if (!existing) throw new Error('Invoice not found');
      await models.invoices.update(finalData, { where: { id } });
      invoiceId = id;
      await models.invoice_items.destroy({ where: { invoice_id: id } });
    } else {
      const created = await models.invoices.create(finalData);
      invoiceId = created.id;
    }

    // === Save Items ===
    const itemRows = items.map(item => ({
      invoice_id: invoiceId,
      code: item.code,
      title: item.title,
      amount: Number(item.amount),
      created_at: new Date(),
      updated_at: new Date(),
    }));
    if (itemRows.length > 0) {
      await models.invoice_items.bulkCreate(itemRows);
    }

    // === Update Entity Balance ===
    await entity.update({
      opening_balance: newOpeningBalance,
      updated_at: new Date(),
    });

    // === Link Invoice to Tenant/Client ===
    if (type === 'tenant') {
      await models.tenant_invoices.create({
        tenant_id,
        invoice_id: invoiceId,
        created_at: new Date(),
        updated_at: new Date(),
      });
    } else {
      await models.client_invoices.create({
        client_id,
        invoice_id: invoiceId,
        created_at: new Date(),
        updated_at: new Date(),
      });
    }

    // === SEND EMAIL WITH INVOICE HTML + OPTIONAL PDF ===
    if (finalData.send_email) {
      await sendInvoiceEmail(finalData, unit, entity, items, invoiceId);
    }

    return {
      id: invoiceId,
      print_invoice: finalData.print_invoice,
    };

  } catch (error) {
    console.error('Error saving invoice:', error);
    throw new Error(error.message || 'Failed to save invoice');
  }
};

// === EMAIL HELPER FUNCTION ===
async function sendInvoiceEmail(finalData, unit, entity, items, invoiceId) {
  console.log("finalData:", finalData)
  const formatCurrency = (amount) => {
    if (amount == null) return '-';
    return new Intl.NumberFormat('en-US', {
      style: 'currency',
      currency: 'USD',
      minimumFractionDigits: 2,
    }).format(amount);
  };

  const formatDate = (date) => {
    if (!date) return '';
    return new Date(date).toLocaleDateString('en-US');
  };

  const recipientName = entity.first_name
    ? `${entity.first_name} ${entity.last_name || ''}`.trim()
    : entity.name || '[ RECIPIENT NAME ]';

  const recipientAddress = entity.street_number || '[ RECIPIENT ADDRESS ]';
  const recipientPhone = entity.phone || '[ RECIPIENT PHONE ]';
  const recipientEmail = entity.email || finalData.receipent_email || '[ RECIPIENT EMAIL ]';

  // === FULL HTML INVOICE EMAIL ===
  const htmlEmail = `
<!DOCTYPE html>
<html>
<head>
  <meta charset="UTF-8">
  <title>Invoice #${finalData.invoice_no}</title>
</head>
<body style="font-family: Arial, sans-serif; margin: 0; padding: 0; background-color: #f4f4f4; padding-top:10px; padding-bottom:10px;">
  <div style="max-width: 800px; margin: 20px auto; background: white; padding: 30px; border-radius: 8px; box-shadow: 0 2px 10px rgba(0,0,0,0.1);">
    <!-- Header -->
    <div style="background: #000; color: white; text-align: center; border-radius: 5px; margin-bottom: 30px;">
      <h2 style="margin: 0; font-size: 24px;">Rental Invoice</h2>
    </div>
    
    <!-- Company and Biller Info -->
    <div style="display: flex; margin-bottom: 20px; gap: 70px !important;">
      <div style="flex: 1; padding-right: 80px; padding-left:20px">
        <div>
          <img src="http://18.220.103.101/assets/ime-systems-logo-07b758a1.svg" alt="IME Systems" style="width: 80px; height: 80px; object-fit: contain; margin-right: 15px;" />
          <h3 style="margin: 0; font-size: 20px;">IME SYSTEMS</h3>
        </div>
      </div>

      <div style="flex: 1; margin-bottom: 25px; padding-right: 40px;">
        <h3 style="margin: 0 0 10px 0; font-size: 16px; font-weight: bold;">Bill From:</h3>
        <p style="margin: 0; font-weight: bold; font-size: 16px;">${unit.name}</p>
        <p style="margin: 5px 0 0 0; font-style: italic;">(Not for Profit Organization)</p>
        <p style="margin: 5px 0 0 0;">57-16 37th Ave, Woodside, NY 11377</p>
        <p style="margin: 5px 0 0 0;">Phone: 718-803-3747</p>
        <p style="margin: 5px 0 0 0;">Email: admin@masjidfatima.org</p>
        <p style="margin: 5px 0 0 0;">EIN: 12-3456784</p>
      </div>
      
      <div style="flex: 1; padding-left: 20px;">
        <h3 style="margin: 0 0 10px 0; font-size: 16px; font-weight: bold;">Bill To:</h3>
        <p style="margin: 0; font-weight: bold; font-size: 16px;">${recipientName}</p>
        <p style="margin: 5px 0 0 0; font-style: italic;">${recipientAddress}</p>
        <p style="margin: 5px 0 0 0; font-style: italic;">Phone: ${recipientPhone}</p>
        <p style="margin: 5px 0 0 0; font-style: italic;">Email: ${recipientEmail}</p>
      </div>
    </div>
    
    <!-- Invoice Details -->
    <div style="display: flex; margin-bottom: 30px; float:right; margin-right: 15px;">
      <div style="flex: 1; width:300px;">
        <table style="width: 100%; border-collapse: collapse;">
          <tr>
            <td style="padding: 8px 0; border-bottom: 1px solid #ddd; font-weight: bold;">Invoice #</td>
            <td style="padding: 8px 0; border-bottom: 1px solid #ddd;">${finalData.invoice_no}</td>
          </tr>
          <tr>
            <td style="padding: 8px 0; border-bottom: 1px solid #ddd; font-weight: bold;">Issue Date: </td>
            <td style="padding: 8px 0; border-bottom: 1px solid #ddd;">${formatDate(finalData.issue_date)}</td>
          </tr>
          <tr>
            <td style="padding: 8px 0; font-weight: bold;">Due Date: </td>
            <td style="padding: 8px 0;">${formatDate(finalData.due_date)}</td>
          </tr>
        </table> 
      </div>
    </div>
    
    <!-- Items Table -->
    <table style="width: 100%; border-collapse: collapse; margin-bottom: 30px;">
      <thead>
        <tr style="background-color: #f0f0f0;">
          <th style="padding: 12px; text-align: left; border: 1px solid #ddd; width: 30%;">Item Code</th>
          <th style="padding: 12px; text-align: left; border: 1px solid #ddd; width: 40%;">Items</th>
          <th style="padding: 12px; text-align: left; border: 1px solid #ddd; width: 30%;">Amount</th>
        </tr>
      </thead>
      <tbody>
        ${items.length > 0 ? items.map(item => `
          <tr>
            <td style="padding: 12px; border: 1px solid #ddd;">${item.code || ''}</td>
            <td style="padding: 12px; border: 1px solid #ddd;">${item.title || ''}</td>
            <td style="padding: 12px; border: 1px solid #ddd;">$${Number(item.amount || 0).toFixed(2)}</td>
          </tr>
        `).join('') : '<tr><td colspan="3" style="padding: 12px; border: 1px solid #ddd; text-align: center;">No items</td></tr>'}
      </tbody>
    </table>
    
    <!-- Note and Totals -->
    <div style="display: flex;">
      <div style="flex: 1; padding-right: 20px; width: 55%;">
        <div style="margin-bottom: 20px;">
          <strong>Note:</strong>
          <p style="margin-top: 5px;">${finalData.note || 'N/A'}</p>
        </div>
      </div>
      
      <div style="flex: 1; padding-left: 20px; width: 40%;">
        <table style="width: 100%; border-collapse: collapse;">
          <tr>
            <td style="padding: 10px; border: 1px solid #ddd; font-weight: bold;">SubTotal</td>
            <td style="padding: 10px; border: 1px solid #ddd; text-align: right;">${formatCurrency(finalData.subtotal)}</td>
          </tr>
          <tr>
            <td style="padding: 10px; border: 1px solid #ddd; font-weight: bold;">Discount</td>
            <td style="padding: 10px; border: 1px solid #ddd; text-align: right;">
              ${finalData.discount_type === '%' ? `${finalData.discount}%` : formatCurrency(finalData.discount)}
            </td>
          </tr>
          <tr style="background-color: #e0e0e0;">
            <td style="padding: 10px; border: 1px solid #ddd; font-weight: bold;">Total</td>
            <td style="padding: 10px; border: 1px solid #ddd; text-align: right; font-weight: bold;">
              ${formatCurrency(finalData.total)}
            </td>
          </tr>
        </table>
      </div>
    </div>
  </div>
</body>
</html>`;

  // === Nodemailer Setup ===
  const transporter = nodemailer.createTransport({
    host: "smtp.gmail.com",
    port: 465,
    secure: true,
    auth: {
      user: process.env.EMAIL_USER || "asasatechdeveloper1@gmail.com",
      pass: process.env.EMAIL_PASS || "ywbg afpp igua bezs",
    },
  });

  const mailOptions = {
    from: `"IMES Systems" <${process.env.EMAIL_USER || "asasatechdeveloper1@gmail.com"}>`,
    to: finalData.receipent_email,
    subject: `Invoice #${finalData.invoice_no} - Rental Invoice`,
    html: htmlEmail,
  };

  await transporter.sendMail(mailOptions);
  console.log(`Invoice email sent to ${finalData.receipent_email}`);
}

const saveEmployeeShiftEntry = async (employeeShiftInput, { auth }) => {
  try {
    if (!models?.employee_shift) {
      throw new Error('Employee Shift model not found.');
    }

    const userId = auth?.userId;
    if (!userId) {
      throw new Error('Unauthorized user');
    }

    const { id, ...input } = employeeShiftInput;

    const timestamp = new Date();
    const baseData = {
      ...input,
      created_by: userId,
      updated_at: timestamp,
    };

    let result;

    if (id) {
      const existing = await models.employee_shift.findByPk(id);
      if (!existing) throw new Error('Shift not found');
      await existing.update(baseData);
      result = existing;
    } else {
      baseData.created_at = timestamp;
      result = await models.employee_shift.create(baseData);
    }

    console.log('Shift record saved:', result?.toJSON?.());
    return !!result;

  } catch (error) {
    console.error('Error in saveEmployeeShiftEntry:', error);
    throw new Error(error.message || 'Failed to save employee shift');
  }
};

const saveShiftRoster = async (rosterInput, { auth }) => {
  try {
    const userId = auth?.userId;
    if (!userId) throw new Error('Unauthorized user');

    const { employee_ids, dates, ...rest } = rosterInput;

    if (!Array.isArray(employee_ids) || employee_ids.length === 0) {
      throw new Error('No employees selected');
    }
    if (!Array.isArray(dates) || dates.length === 0) {
      throw new Error('No dates selected');
    }

    const timestamp = new Date();

    // Fetch all existing rosters for the selected employees
    const existing = await models.shift_roster.findAll({
      where: { employee_id: employee_ids }
    });

    // Build a lookup: key = empId-month-year, value = record ID
    const existingMap = new Map();
    existing.forEach(row => {
      const rowDate = new Date(row.date);
      const key = `${row.employee_id}-${rowDate.getDate()}-${rowDate.getMonth()}-${rowDate.getFullYear()}`;
      existingMap.set(key, row.id);
    });

    const recordsToInsert = [];

    employee_ids.forEach(empId => {
      dates.forEach(date => {
        const d = new Date(date);
        const key = `${empId}-${d.getDate()}-${d.getMonth()}-${d.getFullYear()}`;
        recordsToInsert.push({
          ...rest,
          date: d,
          employee_id: empId,
          added_by: userId,
          last_updated_by: userId,
          created_at: timestamp,
          updated_at: timestamp,
          id: existingMap.get(key) || undefined // update only if exact same date exists
        });
      });
    });

    await models.shift_roster.bulkCreate(recordsToInsert, {
      updateOnDuplicate: [
        'employee_shift_id',
        'remarks',
        'last_updated_by',
        'updated_at',
      ],
    });

    return true;
  } catch (err) {
    console.error('Error in saveShiftRoster:', err);
    throw err;
  }
};

const saveShiftRostersingle = async (rosterInputSingle, { auth }) => {
  try {
    const userId = auth?.userId;
    if (!userId) throw new Error('Unauthorized user');

    const { employee_id, date, ...rest } = rosterInputSingle;

    if (!employee_id) throw new Error('Employee is required');
    if (!date) throw new Error('Date is required');

    const timestamp = new Date();

    const existingRoster = await models.shift_roster.findOne({
      where: {
        employee_id,
        date: new Date(date)
      }
    });

    if (existingRoster) {
      await existingRoster.update({
        ...rest,
        last_updated_by: userId,
        updated_at: timestamp
      });
    } else {
      await models.shift_roster.create({
        ...rest,
        date: new Date(date),
        employee_id,
        added_by: userId,
        created_at: timestamp,
        updated_at: timestamp
      });
    }

    return true;
  } catch (err) {
    console.error('Error in saveShiftRostersingle:', err);
    throw err;
  }
};

const saveInvitation = async (invitationInput, { auth }) => {
  try {
    const userId = auth?.userId;
    if (!userId) throw new Error("Unauthorized user");

    let { email, message, invite_link, otp_code, unit_id } = invitationInput;

    const data = {
      email,
      message,
      invite_link,
      otp_code,
      unit_id,
      created_by: userId,
      created_at: new Date(),
      updated_at: new Date(),
    };

    const result = await models.invitation.create(data);
    console.log("Invitation created:", result.toJSON());

    // ✅ Setup transporter
    const transporter = nodemailer.createTransport({
      host: "smtp.gmail.com",
      port: 465,
      secure: true,
      auth: {
        user: "asasatechdeveloper1@gmail.com",
        pass: "ywbg afpp igua bezs", // Gmail App Password
      },
    });

    await transporter.sendMail({
      from: `"IMES Systems" <asasatechdeveloper1@gmail.com>`,
      to: email,
      subject: "Invitation to Join IMES Systems",
      html: `
        <div style="font-family: Arial, sans-serif; color: #333; line-height: 1.5;">
          <p>Hello,</p>
          <p>You have been invited to join <strong>IMES Systems</strong>.</p>
          <p> This is your OTP: <strong style="font-size:18px; color:#007bff;">${otp_code}</strong>
          </p>
          
          <p>You can download our company application to stay connected with the team from this link:</p>
          <p>
            <a href="${invite_link}" target="_blank" 
              style="display:inline-block; background:#1a73e8; color:#fff; padding:10px 16px; border-radius:5px; text-decoration:none; font-weight:bold;">
              Download IMES App
            </a>
          </p>

          <p>If the button doesn’t work, copy and paste this link into your browser:</p>
          <p><a href="${invite_link}" target="_blank" style="color:#1a73e8;">${invite_link}</a></p>

          <p>Or You Can direct register through our web portal:</p>

          <p><a href="http://localhost:5173/auth/register" target="_blank" style="color:#1a73e8;">http://localhost:5173/auth/register</a></p>
          
          ${message
          ? `<hr style="margin:20px 0; border:none; border-top:1px solid #ddd;" />
                <p style="font-style:italic; color:#555;">${message}</p>`
          : ""
        }

          <p style="margin-top:20px; font-size:12px; color:#777;">— IMES Systems Team</p>
        </div>
      `,
    })


    console.log(`✅ Invitation email sent to ${email}`);

    return true;
  } catch (error) {
    console.error("❌ Error in save invitation:", error);
    throw new Error(error.message);
  }
};

const saveGlobalCurrency = async (currencyInput, { auth }) => {
  try {
    if (!models?.global_currency) {
      throw new Error('global_currency model not found');
    }

    const userId = auth?.userId;
    if (!userId) throw new Error('Unauthorized');

    const created = await models.global_currency.create({
      unit_id: currencyInput.unit_id,
      currency_name: currencyInput.currency_name,
      currency_symbol: currencyInput.currency_symbol,
      currency_code: currencyInput.currency_code,
      is_cryptocurrency: currencyInput.is_cryptocurrency,
      created_by: userId,
      created_at: new Date(),
      updated_at: new Date()
    });

    return created.id; // return the new currency ID
  } catch (error) {
    console.error('Error saving currency:', error.message);
    throw new Error(error.message);
  }
};

const updateRosterEntry = async (rosterupdateInput, { auth }) => {
  try {
    const userId = auth?.userId;
    if (!userId) throw new Error('Unauthorized user');

    const { employee_id, date, RosterId, employee_shift_id, ...rest } = rosterupdateInput;

    if (!employee_id) throw new Error('Employee is required');
    if (!date) throw new Error('Date is required');
    if (!RosterId) throw new Error('RosterId is required');

    const timestamp = new Date();

    const existingRoster = await models.shift_roster.findOne({
      where: { id: RosterId }
    });

    if (existingRoster) {
      await existingRoster.update({
        employee_shift_id: employee_shift_id !== null ? employee_shift_id : null,
        ...rest,
        last_updated_by: userId,
        updated_at: timestamp
      });
    } else {
      await models.shift_roster.create({
        employee_id,
        date: new Date(date),
        employee_shift_id: employee_shift_id !== null ? employee_shift_id : null,
        ...rest,
        added_by: userId,
        created_at: timestamp,
        updated_at: timestamp
      });
    }

    return true;
  } catch (err) {
    console.error('Error in update Roster Entry:', err);
    throw err;
  }
};

const updateGlobalCurrency = async (currencyUpdateInput, { auth }) => {
  try {
    if (!models?.global_currency) {
      throw new Error('global_currency model not found');
    }

    const userId = auth?.userId;
    if (!userId) throw new Error('Unauthorized user');

    const { id, ...rest } = currencyUpdateInput;
    if (!id) throw new Error('Currency ID is required');

    const timestamp = new Date();

    const existingCurrency = await models.global_currency.findOne({
      where: { id }
    });

    if (!existingCurrency) {
      throw new Error(`Currency with ID ${id} not found`);
    }

    await existingCurrency.update({
      ...rest,
      updated_at: timestamp
    });

    return id; // return the updated currency ID
  } catch (err) {
    console.error('Error updating GlobalCurrency:', err.message);
    throw new Error(err.message);
  }
};

const markUpdateStatusHandle = async (markUpdatestatusInput, { auth }) => {
  console.log("📥 markUpdatestatusInput:", markUpdatestatusInput);

  const transaction = await models.sequelize.transaction();
  try {
    if (!models?.temporary_employee) throw new Error("temporary_employee model not found");
    if (!models?.employee) throw new Error("employee model not found");
    if (!models?.user) throw new Error("user model not found");
    if (!models?.user_employee_map) throw new Error("user_employee_map model not found");

    const userId = auth?.userId;
    if (!userId) throw new Error("Unauthorized user");

    const { id, status, message } = markUpdatestatusInput;
    if (!id) throw new Error("Employee ID is required");

    const tempEmployee = await models.temporary_employee.findByPk(id);
    if (!tempEmployee) throw new Error(`Temporary employee with ID ${id} not found`);

    console.log("👤 tempEmployee:", tempEmployee.toJSON());

    // Update temp employee status/message first
    tempEmployee.status = status;
    tempEmployee.message = message || null;
    await tempEmployee.save({ transaction });

    // Approved -> create permanent records
    if (status === 1) {
      console.log("✅ Status approved, promoting employee...");

      const existingUser = await models.user.findOne({
        where: { email: tempEmployee.email },
        transaction
      });
      if (existingUser) throw new Error(`Email ${tempEmployee.email} already exists`);

      if (!tempEmployee.email || !tempEmployee.password || !tempEmployee.user_pass)
        throw new Error("Missing email or password fields in temporary employee");

      const fullName = [tempEmployee.first_name, tempEmployee.last_name].filter(Boolean).join(" ");

      const newUser = await models.user.create(
        {
          name: fullName || tempEmployee.email,
          nick: fullName || tempEmployee.email,
          email: tempEmployee.email,
          password: tempEmployee.password,
          user_pass: tempEmployee.user_pass,
          cutoff_date: null,
          user_group_id: 7,
          status: "Active",
          remember_token: null,
          face_embedding: tempEmployee.face_embedding || null,
          device_id: tempEmployee.device_id || null,
        },
        { transaction }
      );

      const newEmployee = await models.employee.create(
        {
          unit_id: tempEmployee.unit_id ?? null,
          firstname: tempEmployee.first_name || "",
          middlename: tempEmployee.middle_name || null,
          lastname: tempEmployee.last_name || "",
          payroll_id: tempEmployee.payroll_id || null,
          address: tempEmployee.number_and_street || "",
          city: tempEmployee.city || "",
          county: tempEmployee.borough || "",
          state: tempEmployee.state || "",
          zip: tempEmployee.zip_code || "",
          country: tempEmployee.country || "",
          phone: tempEmployee.phone_number || null,
          gender: tempEmployee.gender || "Unknown",
          hire_date: new Date(),
          job_title_id: tempEmployee.job_title_id ?? null,
          job_title: tempEmployee.job_title || "Unknown",
          schedule_id: tempEmployee.schedule_id ?? 1,
          type: tempEmployee.type || "Full-time",
          wage: tempEmployee.wage ?? 0,
          marital_status: tempEmployee.marital_status || "Single",
          exemptions: tempEmployee.exemptions ?? 0,
          social_security_num: tempEmployee.ssn || "",
          department_id: tempEmployee.department_id ?? null,
          birth_date: tempEmployee.birth_date || null,
          status: "Active",
        },
        { transaction }
      );

      await models.user_employee_map.create(
        { user_id: newUser.id, employee_id: newEmployee.id },
        { transaction }
      );

      await transaction.commit();
      return { employeeId: newEmployee.id, userId: newUser.id };
    }

    // Rejected -> delete permanent records if any
    if (status === 2) {
      console.log("❌ Status rejected, cleaning up employee records...");

      const existingUser = await models.user.findOne({
        where: { email: tempEmployee.email },
        transaction
      });

      if (existingUser) {
        // Delete linked employee
        const employeeMap = await models.user_employee_map.findOne({
          where: { user_id: existingUser.id },
          transaction
        });
        if (employeeMap) {
          await models.employee.destroy({
            where: { id: employeeMap.employee_id },
            transaction
          });
          await models.user_employee_map.destroy({
            where: { user_id: existingUser.id },
            transaction
          });
        }

        // Delete user
        await models.user.destroy({
          where: { id: existingUser.id },
          transaction
        });

        console.log(`🗑 Deleted user ${existingUser.id} and linked employee`);
      }

      // Optionally, delete temp employee itself
      // await tempEmployee.destroy({ transaction });

      await transaction.commit();
      return { message: "Rejected employee cleaned up" };
    }

    await transaction.commit();
    return true;

  } catch (err) {
    await transaction.rollback();
    console.error("❌ Error in markUpdateStatusHandle:", err);
    throw new Error(`markUpdateStatusHandle failed: ${err.message}`);
  }
};

const saveInvoiceEntryFromMemorized = async (invoiceInputFromMemorized, { auth }) => {
  try {
    if (
      !models ||
      !models.invoices ||
      !models.invoice_items ||
      !models.tenants ||
      !models.client ||
      !models.tenant_invoices ||
      !models.client_invoices ||
      !models.unit ||
      !models.memorized_invoice // Add check for memorized_invoice model
    ) {
      throw new Error('Required models not found in context');
    }

    const userId = auth?.userId;
    if (!userId) throw new Error('Unauthorized');

    const {
      memorized_id,
      items = [],
      total = 0,
      tenant_id,
      client_id,
      type,
      ...mainData
    } = invoiceInputFromMemorized;

    // Validate required fields
    const requiredFields = ['unit_id', 'issue_date', 'due_date', 'subtotal'];
    for (const field of requiredFields) {
      if (!mainData[field] && mainData[field] !== 0) {
        throw new Error(`Missing required field: ${field}`);
      }
    }

    if (!type || !['tenant', 'client'].includes(type)) {
      throw new Error('Invalid or missing invoice type');
    }
    if (type === 'tenant' && !tenant_id) {
      throw new Error('Missing tenant_id for tenant invoice');
    }
    if (type === 'client' && !client_id) {
      throw new Error('Missing client_id for client invoice');
    }

    let invoice_no = mainData.invoice_no;
    if (!invoice_no) {
      const lastInvoice = await models.invoices.findOne({
        where: {
          invoice_no: {
            [models.Sequelize.Op.like]: 'INV-%'
          }
        },
        order: [['invoice_no', 'DESC']]
      });

      let nextNumber = 1001;
      if (lastInvoice && lastInvoice.invoice_no) {
        const match = lastInvoice.invoice_no.match(/^INV-(\d+)$/);
        if (match) {
          nextNumber = parseInt(match[1], 10) + 1;
        }
      }
      invoice_no = `INV-${nextNumber}`;
    }

    const existingInvoice = await models.invoices.findOne({
      where: { invoice_no }
    });
    if (existingInvoice) throw new Error(`Invoice number ${invoice_no} already exists`);

    let entity;
    if (type === 'tenant') {
      entity = await models.tenants.findByPk(tenant_id);
      if (!entity) throw new Error(`Tenant not found with ID: ${tenant_id}`);
    } else {
      entity = await models.client.findByPk(client_id);
      if (!entity) throw new Error(`Client not found with ID: ${client_id}`);
    }

    const openingBalance = Number(entity.opening_balance || 0);
    const invoiceTotal = Number(total);
    if (isNaN(invoiceTotal) || invoiceTotal < 0) {
      throw new Error('Invalid total value');
    }

    let appliedAmount = 0;
    if (openingBalance < 0) {
      appliedAmount = Math.min(invoiceTotal, Math.abs(openingBalance));
    }

    const invoiceBalance = invoiceTotal - appliedAmount;

    let invoiceStatus = 'unpaid';
    if (invoiceBalance === 0) {
      invoiceStatus = 'paid';
    } else if (appliedAmount > 0) {
      invoiceStatus = 'partial';
    }

    const newOpeningBalance = openingBalance + invoiceTotal;

    const timestamp = new Date();

    const finalData = {
      ...mainData,
      unit_id: mainData.unit_id,
      invoice_no,
      issue_date: new Date(mainData.issue_date),
      due_date: new Date(mainData.due_date),
      note: mainData.note || null,
      subtotal: Number(mainData.subtotal),
      discount_type: mainData.discount_type || null,
      discount: Number(mainData.discount) || 0,
      tenant_id: type === 'tenant' ? tenant_id : null,
      client_id: type === 'client' ? client_id : null,
      type,
      total: invoiceTotal,
      balance: invoiceBalance,
      paid_amount: appliedAmount,
      status: invoiceStatus,
      send_email: mainData.send_email || false,
      print_invoice: mainData.print_invoice || 'false',
      print_fax: mainData.print_fax || false,
      created_by: userId,
      created_at: timestamp,
      updated_at: timestamp,
    };

    const createdInvoice = await models.invoices.create(finalData);
    const invoiceId = createdInvoice.id;

    const itemRows = items.map(item => ({
      invoice_id: invoiceId,
      code: item.code,
      title: item.title,
      amount: Number(item.amount),
      created_at: timestamp,
      updated_at: timestamp,
    }));

    if (itemRows.length > 0) {
      await models.invoice_items.bulkCreate(itemRows);
    }

    await entity.update({
      opening_balance: newOpeningBalance,
      updated_at: timestamp,
    });

    if (type === 'tenant') {
      await models.tenant_invoices.create({
        tenant_id,
        invoice_id: invoiceId,
        created_at: timestamp,
        updated_at: timestamp,
      });
    } else {
      await models.client_invoices.create({
        client_id,
        invoice_id: invoiceId,
        created_at: timestamp,
        updated_at: timestamp,
      });
    }

    // Delete the memorized invoice record
    if (memorized_id) {
      const memorizedInvoice = await models.memorized_invoice.findByPk(memorized_id);
      if (memorizedInvoice) {
        await memorizedInvoice.destroy();
      } else {
        console.warn(`Memorized invoice with ID ${memorized_id} not found`);
      }
    }

    return true;
  } catch (error) {
    console.error('Error saving invoice:', error);
    throw new Error(error.message);
  }
};

const bulksaveInvoiceEntryFromMemorized = async (invoiceInputFromMemorized, { auth }) => {
  try {
    if (
      !models ||
      !models.invoices ||
      !models.invoice_items ||
      !models.tenants ||
      !models.client ||
      !models.tenant_invoices ||
      !models.client_invoices ||
      !models.unit ||
      !models.memorized_invoice // Add check for memorized_invoice model
    ) {
      throw new Error('Required models not found in context');
    }

    const userId = auth?.userId;
    if (!userId) throw new Error('Unauthorized');

    const {
      memorized_id,
      items = [],
      total = 0,
      tenant_id,
      client_id,
      type,
      ...mainData
    } = invoiceInputFromMemorized;

    // Validate required fields
    const requiredFields = ['unit_id', 'issue_date', 'due_date', 'subtotal'];
    for (const field of requiredFields) {
      if (!mainData[field] && mainData[field] !== 0) {
        throw new Error(`Missing required field: ${field}`);
      }
    }

    if (!type || !['tenant', 'client'].includes(type)) {
      throw new Error('Invalid or missing invoice type');
    }
    if (type === 'tenant' && !tenant_id) {
      throw new Error('Missing tenant_id for tenant invoice');
    }
    if (type === 'client' && !client_id) {
      throw new Error('Missing client_id for client invoice');
    }

    let invoice_no = mainData.invoice_no;
    if (!invoice_no) {
      const lastInvoice = await models.invoices.findOne({
        where: {
          invoice_no: {
            [models.Sequelize.Op.like]: 'INV-%'
          }
        },
        order: [['invoice_no', 'DESC']]
      });

      let nextNumber = 1001;
      if (lastInvoice && lastInvoice.invoice_no) {
        const match = lastInvoice.invoice_no.match(/^INV-(\d+)$/);
        if (match) {
          nextNumber = parseInt(match[1], 10) + 1;
        }
      }
      invoice_no = `INV-${nextNumber}`;
    }

    const existingInvoice = await models.invoices.findOne({
      where: { invoice_no }
    });
    if (existingInvoice) throw new Error(`Invoice number ${invoice_no} already exists`);

    let entity;
    if (type === 'tenant') {
      entity = await models.tenants.findByPk(tenant_id);
      if (!entity) throw new Error(`Tenant not found with ID: ${tenant_id}`);
    } else {
      entity = await models.client.findByPk(client_id);
      if (!entity) throw new Error(`Client not found with ID: ${client_id}`);
    }

    const openingBalance = Number(entity.opening_balance || 0);
    const invoiceTotal = Number(total);
    if (isNaN(invoiceTotal) || invoiceTotal < 0) {
      throw new Error('Invalid total value');
    }

    let appliedAmount = 0;
    if (openingBalance < 0) {
      appliedAmount = Math.min(invoiceTotal, Math.abs(openingBalance));
    }

    const invoiceBalance = invoiceTotal - appliedAmount;

    let invoiceStatus = 'unpaid';
    if (invoiceBalance === 0) {
      invoiceStatus = 'paid';
    } else if (appliedAmount > 0) {
      invoiceStatus = 'partial';
    }

    const newOpeningBalance = openingBalance + invoiceTotal;

    const timestamp = new Date();

    const finalData = {
      ...mainData,
      unit_id: mainData.unit_id,
      invoice_no,
      issue_date: new Date(mainData.issue_date),
      due_date: new Date(mainData.due_date),
      note: mainData.note || null,
      subtotal: Number(mainData.subtotal),
      discount_type: mainData.discount_type || null,
      discount: Number(mainData.discount) || 0,
      tenant_id: type === 'tenant' ? tenant_id : null,
      client_id: type === 'client' ? client_id : null,
      type,
      total: invoiceTotal,
      balance: invoiceBalance,
      paid_amount: appliedAmount,
      status: invoiceStatus,
      send_email: mainData.send_email || false,
      print_invoice: mainData.print_invoice || 'false',
      print_fax: mainData.print_fax || false,
      created_by: userId,
      created_at: timestamp,
      updated_at: timestamp,
    };

    const createdInvoice = await models.invoices.create(finalData);
    const invoiceId = createdInvoice.id;

    const itemRows = items.map(item => ({
      invoice_id: invoiceId,
      code: item.code,
      title: item.title,
      amount: Number(item.amount),
      created_at: timestamp,
      updated_at: timestamp,
    }));

    if (itemRows.length > 0) {
      await models.invoice_items.bulkCreate(itemRows);
    }

    await entity.update({
      opening_balance: newOpeningBalance,
      updated_at: timestamp,
    });

    if (type === 'tenant') {
      await models.tenant_invoices.create({
        tenant_id,
        invoice_id: invoiceId,
        created_at: timestamp,
        updated_at: timestamp,
      });
    } else {
      await models.client_invoices.create({
        client_id,
        invoice_id: invoiceId,
        created_at: timestamp,
        updated_at: timestamp,
      });
    }

    // Delete the memorized invoice record
    if (memorized_id) {
      const memorizedInvoice = await models.memorized_invoice.findByPk(memorized_id);
      if (memorizedInvoice) {
        await memorizedInvoice.destroy();
      } else {
        console.warn(`Memorized invoice with ID ${memorized_id} not found`);
      }
    }

    return true;
  } catch (error) {
    console.error('Error saving invoice:', error);
    throw new Error(error.message);
  }
};

const saveMemorizedEntry = async (invoiceInput, { auth }) => {
  try {
    if (!models?.memorized_invoice) {
      throw new Error('memorized_invoice model not found');
    }

    const userId = auth?.userId;
    if (!userId) throw new Error('Unauthorized');

    const { recurring_invoice_id, invoice_pay_month, unit_id } = invoiceInput;

    const created = await models.memorized_invoice.create({
      recurring_invoice_id,
      invoice_pay_month,
      unit_id,
      status: false,
      created_by: userId,
      created_at: new Date(),
      updated_at: new Date()
    });

    return created.id;
  } catch (error) {
    console.error('Error saving invoice:', error.message);
    throw new Error(error.message);
  }
};

const MakeRecurringInvoiceEntry = async (recurringInvoiceInput, { auth }) => {
  try {
    if (
      !models ||
      !models.recurring_invoices ||
      !models.recurring_invoice_items ||
      !models.tenants ||
      !models.client ||
      !models.tenant_recurring_invoices ||
      !models.client_recurring_invoices ||
      !models.unit
    ) {
      throw new Error('Required models not found in context');
    }

    const userId = auth?.userId || recurringInvoiceInput.created_by;
    if (!userId) throw new Error('Unauthorized');

    const {
      id,
      items = [],
      total = 0,
      tenant_id,
      client_id,
      type,
      ...mainData
    } = recurringInvoiceInput;

    // Validate invoice type
    if (!type || !['tenant', 'client'].includes(type)) {
      throw new Error('Invalid or missing invoice type');
    }
    if (type === 'tenant' && !tenant_id) {
      throw new Error('Missing tenant_id for tenant recurring invoice');
    }
    if (type === 'client' && !client_id) {
      throw new Error('Missing client_id for client recurring invoice');
    }

    // Validate title uniqueness (assuming title is unique like invoice_no)
    if (!id && mainData.title) {
      const existingInvoice = await models.recurring_invoices.findOne({ where: { title: mainData.title } });
      if (existingInvoice) throw new Error(`Recurring invoice title ${mainData.title} already exists`);
    }

    // Validate entity (tenant or client)
    let entity;
    if (type === 'tenant') {
      entity = await models.tenants.findByPk(tenant_id);
      if (!entity) throw new Error(`Tenant not found with ID: ${tenant_id}`);
    } else {
      entity = await models.client.findByPk(client_id);
      if (!entity) throw new Error(`Client not found with ID: ${client_id}`);
    }

    // Validate total
    const invoiceTotal = Number(total);
    if (isNaN(invoiceTotal) || invoiceTotal < 0) {
      throw new Error('Invalid total value');
    }

    // Calculate balance impact (assuming recurring invoices affect opening balance)
    const openingBalance = Number(entity.opening_balance || 0);
    const appliedAmount = 0; // Recurring invoices may not apply payments immediately
    const invoiceBalance = invoiceTotal; // Balance is total since no payments applied yet

    let invoiceStatus = 'active'; // Default for recurring invoices
    if (invoiceBalance === 0) {
      invoiceStatus = 'inactive'; // Adjust based on your logic
    }

    const newOpeningBalance = openingBalance + invoiceTotal;

    // Prepare final data for recurring invoice
    const finalData = {
      ...mainData,
      unit_id: mainData.unit_id,
      title: mainData.title,
      start_date: new Date(mainData.start_date),
      end_date: mainData.end_date ? new Date(mainData.end_date) : null,
      amount: Number(mainData.amount),
      frequency: mainData.frequency || null,
      tenant_id: type === 'tenant' ? tenant_id : null,
      client_id: type === 'client' ? client_id : null,
      type,
      total: invoiceTotal,
      balance: invoiceBalance,
      paid_amount: appliedAmount,
      status: invoiceStatus,
      created_by: userId,
      created_at: id ? undefined : new Date(),
      updated_at: new Date(),
    };

    console.log('finalData:', JSON.stringify(finalData, null, 2));

    let invoiceId;

    // Create or update recurring invoice
    if (id && id > 0) {
      const existing = await models.recurring_invoices.findByPk(id);
      if (!existing) throw new Error('Recurring invoice not found');

      await models.recurring_invoices.update(finalData, { where: { id } });
      invoiceId = id;

      // Remove existing items
      await models.recurring_invoice_items.destroy({ where: { recurring_invoice_id: id } });
    } else {
      const created = await models.recurring_invoices.create(finalData);
      invoiceId = created.id;
    }

    // Create item rows
    const itemRows = items.map(item => ({
      recurring_invoice_id: invoiceId,
      code: item.code,
      title: item.title,
      amount: Number(item.amount),
      created_at: new Date(),
      updated_at: new Date(),
    }));

    if (itemRows.length > 0) {
      await models.recurring_invoice_items.bulkCreate(itemRows);
    }

    // Update entity opening balance
    await entity.update({
      opening_balance: newOpeningBalance,
      updated_at: new Date(),
    });

    // Create association in tenant_recurring_invoices or client_recurring_invoices
    if (type === 'tenant') {
      await models.tenant_recurring_invoices.create({
        tenant_id,
        recurring_invoice_id: invoiceId,
        created_at: new Date(),
        updated_at: new Date(),
      });
    } else {
      await models.client_recurring_invoices.create({
        client_id,
        recurring_invoice_id: invoiceId,
        created_at: new Date(),
        updated_at: new Date(),
      });
    }

    return invoiceId;
  } catch (error) {
    console.error('Error saving recurring invoice:', error);
    throw new Error(error.message);
  }
};

const updateInvoiceEntry = async (invoiceUpdateInput, { auth }) => {
  try {
    if (
      !models ||
      !models.invoices ||
      !models.invoice_items ||
      !models.tenants ||
      !models.client ||
      !models.tenant_invoices ||
      !models.client_invoices ||
      !models.unit
    ) {
      throw new Error('Required models not found in context');
    }

    const userId = auth?.userId || invoiceUpdateInput.updated_by;
    if (!userId) throw new Error('Unauthorized');

    const {
      id,
      items = [],
      total,
      tenant_id,
      client_id,
      type,
      ...mainData
    } = invoiceUpdateInput;

    if (!id) throw new Error('Invoice ID is required for update');

    const requiredFields = ['unit_id', 'invoice_no', 'issue_date', 'due_date', 'subtotal'];
    for (const field of requiredFields) {
      if (mainData[field] === undefined && mainData[field] !== 0) {
        throw new Error(`Missing required field: ${field}`);
      }
    }

    if (!type || !['tenant', 'client'].includes(type)) {
      throw new Error('Invalid or missing invoice type');
    }
    if (type === 'tenant' && !tenant_id) {
      throw new Error('Missing tenant_id for tenant invoice');
    }
    if (type === 'client' && !client_id) {
      throw new Error('Missing client_id for client invoice');
    }

    if (mainData.unit_id) {
      const unit = await models.unit.findByPk(mainData.unit_id);
      if (!unit) throw new Error(`Unit not found with ID: ${mainData.unit_id}`);
    }

    if (mainData.invoice_no) {
      const existingInvoice = await models.invoices.findOne({
        where: { invoice_no: mainData.invoice_no, id: { [models.Sequelize.Op.ne]: id } },
      });
      if (existingInvoice) throw new Error(`Invoice number ${mainData.invoice_no} already exists`);
    }

    const existingInvoice = await models.invoices.findByPk(id);
    if (!existingInvoice) throw new Error('Invoice not found');

    let entity;
    if (type === 'tenant') {
      entity = await models.tenants.findByPk(tenant_id);
      if (!entity) throw new Error(`Tenant not found with ID: ${tenant_id}`);
    } else {
      entity = await models.client.findByPk(client_id);
      if (!entity) throw new Error(`Client not found with ID: ${client_id}`);
    }

    const openingBalance = Number(entity.opening_balance || 0);
    const invoiceTotal = Number(total || existingInvoice.total);
    if (isNaN(invoiceTotal) || invoiceTotal < 0) {
      throw new Error('Invalid total value');
    }

    let appliedAmount = 0;
    if (openingBalance < 0) {
      appliedAmount = Math.min(invoiceTotal, Math.abs(openingBalance));
    }

    const invoiceBalance = invoiceTotal - appliedAmount;

    let invoiceStatus = 'unpaid';
    if (invoiceBalance === 0) {
      invoiceStatus = 'paid';
    } else if (appliedAmount > 0) {
      invoiceStatus = 'partial';
    }

    const previousTotal = Number(existingInvoice.total || 0);
    const newOpeningBalance = openingBalance - previousTotal + invoiceTotal;

    const finalData = {
      ...mainData,
      unit_id: mainData.unit_id,
      invoice_no: mainData.invoice_no,
      issue_date: new Date(mainData.issue_date),
      due_date: new Date(mainData.due_date),
      note: mainData.note || null,
      subtotal: Number(mainData.subtotal),
      discount_type: mainData.discount_type || null,
      discount: Number(mainData.discount) || 0,
      tenant_id: type === 'tenant' ? tenant_id : null,
      client_id: type === 'client' ? client_id : null,
      type,
      total: invoiceTotal,
      balance: invoiceBalance,
      paid_amount: appliedAmount,
      status: invoiceStatus,
      send_email: mainData.send_email || existingInvoice.send_email || 'false',
      print_invoice: mainData.print_invoice || existingInvoice.print_invoice || 'false',
      print_fax: mainData.print_fax || existingInvoice.print_fax || 'false',
      updated_at: new Date(),
      updated_by: userId,
    };

    console.log('finalData:', JSON.stringify(finalData, null, 2));

    await models.invoices.update(finalData, { where: { id } });

    await models.invoice_items.destroy({ where: { invoice_id: id } });

    const itemRows = items.map(item => ({
      invoice_id: id,
      code: item.code,
      title: item.title,
      amount: Number(item.amount) || 0,
      created_at: new Date(),
      updated_at: new Date(),
    }));

    if (itemRows.length > 0) {
      await models.invoice_items.bulkCreate(itemRows);
    }

    await entity.update({
      opening_balance: newOpeningBalance,
      updated_at: new Date(),
    });

    if (type === 'tenant') {
      await models.tenant_invoices.destroy({ where: { invoice_id: id } });
      await models.tenant_invoices.create({
        tenant_id,
        invoice_id: id,
        created_at: new Date(),
        updated_at: new Date(),
      });
    } else {
      await models.client_invoices.destroy({ where: { invoice_id: id } });
      await models.client_invoices.create({
        client_id,
        invoice_id: id,
        created_at: new Date(),
        updated_at: new Date(),
      });
    }

    return id;
  } catch (error) {
    console.error('Error updating invoice:', error.message);
    throw new Error(error.message);
  }
};

const updatedesignation = async (designationUpdateInput, { auth }) => {
  try {
    if (!models || !models.designation) {
      throw new Error('Designation model not found in context');
    }

    const userId = auth?.userId || designationUpdateInput.updated_by;
    if (!userId) throw new Error('Unauthorized');
    const { id, ...mainData } = designationUpdateInput;
    if (!id) throw new Error('Designation ID is required for update');
    const existingDesignation = await models.designation.findByPk(id);
    if (!existingDesignation) {
      throw new Error('Designation not found');
    }

    await models.designation.update(
      {
        ...mainData,
        updated_at: new Date(),
        updated_by: userId,
      },
      { where: { id } }
    );

    return id;
  } catch (error) {
    console.error('Error updating designation:', error.message);
    throw new Error(error.message);
  }
};

const updatedepartment = async (departmentUpdateInput, { auth }) => {
  try {
    if (!models || !models.department) {
      throw new Error('department model not found in context');
    }

    const userId = auth?.userId || departmentUpdateInput.updated_by;
    if (!userId) throw new Error('Unauthorized');
    const { id, ...mainData } = departmentUpdateInput;
    if (!id) throw new Error('department ID is required for update');
    const existingDepartment = await models.department.findByPk(id);
    if (!existingDepartment) {
      throw new Error('department not found');
    }

    await models.department.update(
      {
        ...mainData,
        updated_at: new Date(),
        updated_by: userId,
      },
      { where: { id } }
    );

    return id;
  } catch (error) {
    console.error('Error updating department:', error.message);
    throw new Error(error.message);
  }
};

const updateRecuuringInvoiceEntry = async (updateRecurringInvoiceInput, { auth }) => {
  try {
    if (!models || !models.recurring_invoices) {
      throw new Error('Required models not found in context');
    }
    const userId = auth?.userId || updateRecurringInvoiceInput.updated_by;
    if (!userId) throw new Error('Unauthorized');
    const {
      id,
      ...mainData
    } = updateRecurringInvoiceInput;
    if (!id) throw new Error('Invoice ID is required for update');
    const existingInvoice = await models.recurring_invoices.findByPk(id);
    if (!existingInvoice) {
      throw new Error('Invoice not found');
    }
    await models.recurring_invoices.update(
      {
        ...mainData,
        updated_at: new Date(),
        updated_by: userId,
      },
      { where: { id } }
    );

    return id;
  } catch (error) {
    console.error('Error updating invoice:', error.message);
    throw new Error(error.message);
  }
};

const saveOccupancyEntry = async (occupancyInput, { auth }) => {
  const { id, created_by, items = [], ...input } = occupancyInput

  const userId = auth?.userId || occupancyInput.created_by;
  if (!userId) throw new Error('Unauthorized user')

  const finalInput = {
    ...input,
    created_by: userId,
    created_at: new Date(),
    updated_at: new Date(),
  }

  let agreement;

  if (id && id > 0) {
    agreement = await models.agreement.findByPk(id)
    if (!agreement) throw new Error('Agreement not found')
    await agreement.update(finalInput)
  } else {
    agreement = await models.agreement.create(finalInput)
  }

  // Save items
  if (items.length > 0) {
    const agreementItems = items.map(i => ({
      ...i,
      agreement_id: agreement.id,
      created_at: new Date(),
      updated_at: new Date(),
    }));

    await models.agreement_items.bulkCreate(agreementItems, {
      updateOnDuplicate: ['item_number', 'name', 'amount', 'updated_at'],
    });
  }

  // 🔥 Fetch and return agreement with tenant and property name
  const populatedAgreement = await models.agreement.findByPk(agreement.id, {
    include: [
      {
        model: models.tenants,
        as: 'tenant',
        attributes: ['id', 'first_name', 'last_name', 'corporation_name']
      },
      {
        model: models.property,
        as: 'property',
        attributes: ['id', 'name']
      }
    ]
  });

  console.log(populatedAgreement.toJSON(), "populatedAgreement");

  return populatedAgreement?.toJSON();
};

const saveRentalcontractEntry = async (rentalcontractInput, { auth }) => {
  try {
    const { items, user_id, ...rest } = rentalcontractInput;

    // === Ensure auth user exists ===
    const userId = auth?.userId || null;
    if (!userId) throw new Error("Unauthorized user: missing auth.userId");

    // === Final data for rental contract ===
    const finalInput = {
      ...rest,
      user_id: user_id || null,
      created_by: userId,
      created_at: new Date(),
      updated_at: new Date(),
    };

    // === Create rental contract ===
    const rentalcontract = await models.agreement.create(finalInput);

    // === Save associated items if provided ===
    if (Array.isArray(items) && items.length > 0) {
      const newItems = items.map(item => ({
        ...item,
        agreement_id: rentalcontract.id,
        created_at: new Date(),
        updated_at: new Date(),
      }));
      await models.agreement_items.bulkCreate(newItems);
    }

    return true;
  } catch (error) {
    console.error("Error saving rental contract:", error.message);
    return false;
  }
};

const savePropertyOwnerEntry = async (owners, { auth }) => {
  if (!Array.isArray(owners) || !owners.length) {
    throw new Error("No owners provided");
  }

  const ids = [];

  for (const propertyownerInput of owners) {
    const { id, email, ...input } = propertyownerInput;

    try {
      if (!models || !models.owner) {
        throw new Error('Property owner model not found (check your models)');
      }

      const userId = auth?.userId || propertyownerInput.created_by;
      if (!userId) throw new Error('Unauthorized user');

      const finalInput = {
        ...input,
        email,
        created_by: userId,
        created_at: new Date(),
        updated_at: new Date(),
      };

      if (id && id > 0) {
        const existing = await models.owner.findByPk(id);
        if (!existing) throw new Error('Property owner not found');

        const emailExists = await models.owner.findOne({
          where: { email, id: { [models.Sequelize.Op.ne]: id } },
        });

        if (emailExists) throw new Error('This email already exists');

        await models.owner.update(finalInput, { where: { id } });
        ids.push(id);
      } else {
        const emailExists = await models.owner.findOne({ where: { email } });
        if (emailExists) throw new Error('This email already exists');

        const created = await models.owner.create(finalInput);
        console.log("Created record:", created.toJSON());
        ids.push(created.id);
      }
    } catch (error) {
      console.error('Error saving owner:', error.message);
      throw new Error(error.message);
    }
  }

  return ids;
};

const saveAttendanceEntry = async (attendanceInput, { auth }) => {
  const userId = auth?.userId || attendanceInput.added_by;
  if (!userId) {
    console.error("Unauthorized user - no userId");
    return null;
  }

  const createdRecords = [];
  const { dates, date, employee_ids, ...rest } = attendanceInput;

  // Determine which dates to use
  const datesToProcess = dates && dates.length > 0 ? dates : [date];

  // Helper to format datetime
  const formatDateTime = (day, time) => {
    const dateTime = new Date(`${day}T${time}`);
    const pad = n => String(n).padStart(2, '0');
    return `${dateTime.getFullYear()}-${pad(dateTime.getMonth() + 1)}-${pad(dateTime.getDate())} ${pad(dateTime.getHours())}:${pad(dateTime.getMinutes())}:${pad(dateTime.getSeconds())}`;
  };

  try {
    if (Array.isArray(employee_ids) && employee_ids.length > 0) {
      for (const empId of employee_ids) {
        for (const day of datesToProcess) {
          // Build proper datetime strings without dayjs
          let clockIn = null;
          let clockOut = null;

          if (attendanceInput.clock_in_time) {
            clockIn = formatDateTime(day, attendanceInput.clock_in_time);
          }
          if (attendanceInput.clock_out_time) {
            clockOut = formatDateTime(day, attendanceInput.clock_out_time);
          }

          const existing = await models.employee_attendance.findOne({
            where: { employee_id: empId, date: day }
          });

          if (existing && !attendanceInput.overwrite_attendance) {
            continue;
          }
          if (existing && attendanceInput.overwrite_attendance) {
            await existing.destroy();
          }

          const finalInput = {
            ...rest,
            date: day,
            clock_in_time: clockIn,
            clock_out_time: clockOut,
            employee_id: empId,
            added_by: userId
          };

          const attendance = await models.employee_attendance.create(finalInput);
          createdRecords.push(attendance);
        }
      }
    } else {
      console.error("No employees provided");
      return null;
    }

    return createdRecords.map(r => r.get({ plain: true }));

  } catch (error) {
    console.error("Error saving attendance entry:", error);
    return null;
  }
};

const saveAttendanceSingleEntry = async (attendanceInputSingle, { auth }) => {
  const userId = auth?.userId;
  if (!userId) {
    console.error("Unauthorized user - no userId");
    return [{
      id: null,
      unit_id: null,
      employee_id: null,
      date: null,
      status: null,
      clock_in_time: null,
      clock_out_time: null,
      working_from: null,
      late: null,
      half_day: null,
      overwrite_attendance: null,
      added_by: null,
      created_at: null,
      updated_at: null,
      success: false,
      message: "Unauthorized user - no userId",
    }];
  }

  const {
    id,
    unit_id,
    employee_id,
    date,
    status,
    clock_in_time,
    clock_out_time,
    working_from,
    late,
    half_day,
  } = attendanceInputSingle;

  const formatDateTime = (day, time) => {
    if (!time) return null;
    const dateTime = new Date(`${day}T${time}`);
    const pad = n => String(n).padStart(2, '0');
    return `${dateTime.getFullYear()}-${pad(dateTime.getMonth() + 1)}-${pad(dateTime.getDate())} ${pad(dateTime.getHours())}:${pad(dateTime.getMinutes())}:${pad(dateTime.getSeconds())}`;
  };
  const clockIndate = formatDateTime(date);

  console.log('Shift roster date:', clockIndate);
  try {
    const existingRoaster = await models.shift_roster.findOne({
      where: {
        employee_id: employee_id,
        date: date,
      },
    });

    console.log('Shift roster check:', existingRoaster);

    if (!existingRoaster) {
      console.warn(`⚠️ No shift roaster assigned for employee ${employee_id} on ${date}`);
      return [{
        id: null,
        unit_id: null,
        employee_id: null,
        date: null,
        status: null,
        clock_in_time: null,
        clock_out_time: null,
        working_from: null,
        late: null,
        half_day: null,
        overwrite_attendance: null,
        added_by: null,
        created_at: null,
        updated_at: null,
        success: false,
        message: "No shift roaster assigned for this employee on this date.",
      }];
    }

    const clockIn = formatDateTime(date, clock_in_time);
    const clockOut = formatDateTime(date, clock_out_time);

    let attendanceRecord;

    if (id) {
      await models.employee_attendance.update(
        {
          unit_id,
          employee_id,
          date,
          status,
          clock_in_time: clockIn,
          clock_out_time: clockOut,
          working_from,
          late,
          half_day,
          updated_at: new Date(),
        },
        { where: { id } }
      );

      attendanceRecord = await models.employee_attendance.findOne({ where: { id }, raw: true });
    } else {
      const newRecord = await models.employee_attendance.create({
        unit_id,
        employee_id,
        date,
        status,
        clock_in_time: clockIn,
        clock_out_time: clockOut,
        working_from,
        late,
        half_day,
        added_by: userId,
        created_at: new Date(),
      });

      attendanceRecord = newRecord.get({ plain: true });
    }

    return [{
      ...attendanceRecord,
      success: true,
      message: "Attendance saved successfully.",
    }];

  } catch (error) {
    console.error("❌ Error saving single attendance entry:", error);
    return [{
      id: null,
      unit_id: null,
      employee_id: null,
      date: null,
      status: null,
      clock_in_time: null,
      clock_out_time: null,
      working_from: null,
      late: null,
      half_day: null,
      overwrite_attendance: null,
      added_by: null,
      created_at: null,
      updated_at: null,
      success: false,
      message: "Error saving single attendance entry.",
    }];
  }
};

// const saveAttendanceSingleEntry = async (attendanceInputSingle, { auth }) => {

//   console.log('save Attendance Single Entry', attendanceInputSingle);

//   const userId = auth?.userId;
//   if (!userId) {
//     console.error("Unauthorized user - no userId");
//     return [];
//   }

//   const {
//     id,
//     unit_id,
//     employee_id,
//     date,
//     status,
//     clock_in_time,
//     clock_out_time,
//     working_from,
//     late,
//     half_day
//   } = attendanceInputSingle;


//   const formatDateTime = (day, time) => {
//     if (!time) return null;
//     const dateTime = new Date(`${day}T${time}`);
//     const pad = n => String(n).padStart(2, '0');
//     return `${dateTime.getFullYear()}-${pad(dateTime.getMonth() + 1)}-${pad(dateTime.getDate())} ${pad(dateTime.getHours())}:${pad(dateTime.getMinutes())}:${pad(dateTime.getSeconds())}`;
//   };

//   try {
//     const clockIn = formatDateTime(date, clock_in_time);
//     const clockOut = formatDateTime(date, clock_out_time);

//     let attendanceRecord;

//     if (id) {
//       await models.employee_attendance.update(
//         {
//           unit_id,
//           employee_id,
//           date,
//           status,
//           clock_in_time: clockIn,
//           clock_out_time: clockOut,
//           working_from,
//           late,
//           half_day,
//           updated_at: new Date()
//         },
//         { where: { id } }
//       );

//       attendanceRecord = await models.employee_attendance.findOne({ where: { id }, raw: true });
//     } else {
//       const newRecord = await models.employee_attendance.create({
//         unit_id,
//         employee_id,
//         date,
//         status,
//         clock_in_time: clockIn,
//         clock_out_time: clockOut,
//         working_from,
//         late,
//         half_day,
//         added_by: userId,
//         created_at: new Date()
//       });

//       attendanceRecord = newRecord.get({ plain: true });
//     }

//     // Schema expects [Attendance!]!
//     return [attendanceRecord];

//   } catch (error) {
//     console.error("Error saving single attendance entry:", error);
//     return [];
//   }
// };

const saveleave = async (leaveInput, { auth }) => {
  try {
    const userId = auth?.userId;
    if (!userId) throw new Error('Unauthorized user');

    const data = {
      ...leaveInput,
      date_range: Array.isArray(leaveInput.date_range) ? leaveInput.date_range : null,
      created_by: userId,
      created_at: new Date(),
      updated_at: new Date(),
    };

    const result = await models.leave.create(data);
    console.log('Leave created:', result.toJSON());

    return true;
  } catch (error) {
    console.error('Error in save leave entry:', error.message);
    throw new Error(error.message);
  }
};

const SaveLeaveEmployee = async (emp_leaveInput, { auth }) => {
  try {
    const userId = auth?.userId;
    if (!userId) throw new Error('Unauthorized user');

    const data = {
      ...emp_leaveInput,
      date_range: Array.isArray(emp_leaveInput.date_range) ? emp_leaveInput.date_range : null,
      created_by: userId,
      created_at: new Date(),
      updated_at: new Date(),
    };

    const result = await models.leave.create(data);
    console.log('Leave created:', result.toJSON());

    return true;
  } catch (error) {
    console.error('Error in save leave entry:', error.message);
    throw new Error(error.message);
  }
};

const saveLeaveEmpApp = async (emp_leaveInput, { auth }) => {
  try {
    const userId = auth?.userId;
    if (!userId) throw new Error('Unauthorized user');

    const data = {
      ...emp_leaveInput,
      date_range: Array.isArray(emp_leaveInput.date_range) ? emp_leaveInput.date_range : null,
      created_by: userId,
      created_at: new Date(),
      updated_at: new Date(),
    };

    const result = await models.leave.create(data);
    console.log('Leave created:', result.toJSON());

    // Return EmpleaveResponse shape
    return {
      success: true,
      message: 'Leave application submitted successfully',
    };
  } catch (error) {
    console.error('Error in save leave entry:', error.message);

    // Return failure response matching EmpleaveResponse
    return {
      success: false,
      message: error.message || 'Failed to submit leave application',
    };
  }
};

const saveleavetype = async (leaveTypeInput, { auth }) => {
  try {
    const userId = auth?.userId;
    if (!userId) throw new Error('Unauthorized user');

    const {
      entitlement,
      applicability,
      ...base
    } = leaveTypeInput;

    const data = {
      ...base,
      effective_after: entitlement.effective_after,
      allowed_probation: entitlement.allowed_probation,
      unused_leave: entitlement.unused_leave,
      over_utilization: entitlement.over_utilization,
      allowed_notice: entitlement.allowed_notice,

      gender: (applicability.gender || []).join(','),
      marital_status: (applicability.marital_status || []).join(','),
      department: (applicability.department || []).join(','),
      designation: (applicability.designation || []).join(','),
      user_role: (applicability.user_role || []).join(','),

      created_at: new Date(),
      updated_at: new Date(),
    };

    const result = await models.leave_types.create(data);
    console.log('Leave Type created:', result.toJSON());
    return true;

  } catch (error) {
    console.error('Error in saveleavetype:', error);
    throw new Error(error.message);
  }
};

const savedesignation = async (designationInput, { auth }) => {
  try {
    const userId = auth?.userId;
    if (!userId) throw new Error('Unauthorized user');
    const { name, parent, unit_id } = designationInput;
    const data = {
      name,
      parent,
      unit_id,
      created_by: userId,
      created_at: new Date(),
      updated_at: new Date(),
    };

    const result = await models.designation.create(data);
    console.log('Designation created:', result.toJSON());

    return true;
  } catch (error) {
    console.error('Error in save designation:', error);
    throw new Error(error.message);
  }
};

const savedepartment = async (departmentInput, { auth }) => {
  try {
    const userId = auth?.userId;
    if (!userId) throw new Error('Unauthorized user');
    const { name, parent, unit_id } = departmentInput;
    const data = {
      name,
      parent,
      unit_id,
      created_by: userId,
      created_at: new Date(),
      updated_at: new Date(),
    };

    const result = await models.department.create(data);
    console.log('department created:', result.toJSON());

    return true;
  } catch (error) {
    console.error('Error in save department:', error);
    throw new Error(error.message);
  }
};

const saveholiday = async (holidayInput, { auth }) => {
  try {
    const userId = auth?.userId;
    if (!userId) throw new Error('Unauthorized user');

    // Common data for all records
    const commonData = {
      department: Array.isArray(holidayInput.department)
        ? holidayInput.department
        : [holidayInput.department],
      designation: Array.isArray(holidayInput.designation)
        ? holidayInput.designation
        : [holidayInput.designation],
      employee_type: Array.isArray(holidayInput.employee_type)
        ? holidayInput.employee_type
        : [holidayInput.employee_type],
      unit_id: holidayInput.unit_id,
      created_by: userId,
      created_at: new Date(),
      updated_at: new Date(),
    };

    const holidayRecords = holidayInput.repeats.map(r => ({
      ...commonData,
      date: r.date,
      occasion: r.occasion
    }));

    // Bulk insert into DB
    const result = await models.holiday.bulkCreate(holidayRecords);

    console.log('Holidays created:', result.map(r => r.toJSON()));

    return true;
  } catch (error) {
    console.error('Error in save holiday:', error);
    throw new Error(error.message);
  }
};

const saveproject = async (projectInput, { auth }) => {
  try {
    const userId = auth?.userId;
    if (!userId) throw new Error('Unauthorized user');

    const data = {
      ...projectInput,
      team: Array.isArray(projectInput.team) ? projectInput.team.join(',') : projectInput.team,
      created_by: userId,
      created_at: new Date(),
      updated_at: new Date(),
    };
    const result = await models.projects.create(data);
    console.log('projects created:', result.toJSON());
    return true;
  } catch (error) {
    console.error('Error in save projects entry:', error.message);
    throw new Error(error.message);
  }
};

const savetask = async (taskInput, { auth }) => {
  try {
    const userId = auth?.userId;
    if (!userId) throw new Error('Unauthorized user');

    // Extract employee IDs from team (if provided)
    const employeeIds = Array.isArray(taskInput.team) ? taskInput.team : [];

    const taskData = {
      title: taskInput.title,
      category: taskInput.category,
      project: taskInput.project, // ✅ add this line
      start_date: taskInput.start_date,
      end_date: taskInput.end_date,
      estimated_hours: taskInput.estimated_hours,
      status: taskInput.status || 'Incomplete',
      description: taskInput.description,
      unit_id: taskInput.unit_id,
      created_by: userId,
      created_at: new Date(),
      updated_at: new Date(),
    };

    const task = await models.tasks.create(taskData);
    console.log('Task created:', task.toJSON());

    if (employeeIds.length > 0) {
      const taskEmployees = employeeIds.map(empId => ({
        task_id: task.id,
        employee_id: empId,
        created_at: new Date(),
        updated_at: new Date(),
      }));

      await models.task_employee.bulkCreate(taskEmployees);
      console.log('Task employees linked:', taskEmployees);
    }

    return true;
  } catch (error) {
    console.error('Error saving task:', error.message);
    throw new Error(error.message);
  }
};


// const save_task_approved = async (_, { taskApprovedInput }, { auth }) => {
//   try {
//     const userId = auth?.userId;
//     if (!userId) throw new Error('Unauthorized user');

//     const data = {
//       ...taskApprovedInput,
//       created_by: userId,
//       created_at: new Date(),
//       updated_at: new Date(),
//     }
//     const result = await TaskApproved.create(data)
//     return result
//   } catch (err) {
//     console.error('Error creating TaskApproved:', err)
//     throw new Error('Failed to create task')
//   }
// };

// const update_task_approved = async (_, { updateTaskApprovedInput }) => {
//   try {
//     const { id, ...updateData } = updateTaskApprovedInput
//     updateData.updated_at = new Date()
//     await TaskApproved.update(updateData, { where: { id } })
//     return await TaskApproved.findByPk(id)
//   } catch (err) {
//     console.error('Error updating TaskApproved:', err)
//     throw new Error('Failed to update task')
//   }
// };

const delete_task_approved = async (id) => {
  console.log(id, "delete Task Approved");

  try {
    const chartAccount = await models.task_approved.findByPk(id)
    if (!chartAccount) return false

    await models.task_approved.destroy({
      where: { id }
    })

    return true
  } catch (error) {
    console.error('Error delete task approved', error)
    return false
  }
};

const deleteService = async (id) => {
  console.log(id, "delete Service");

  try {
    const DeleteService = await models.client_service.findByPk(id)
    if (!DeleteService) return false

    await models.client_service.destroy({
      where: { id }
    })

    return true
  } catch (error) {
    console.error('Error delete service', error)
    return false
  }
};


const logUserActivityHandle = async (input) => {
  try {
    // Create activity log
    const activity = await models.user_activity.create({
      user_id: input.user_id || null,
      activity_type: input.activity_type || null,
      activity_time: input.activity_time ? new Date(input.activity_time) : new Date(),
      details: input.details || null,
      status: input.status || null,
      ip_address: input.ip_address || null,
      user_agent: input.user_agent || null,
      unit_id: input.unit_id || null,
      source: input.source || null,
    });

    // Return GraphQL-friendly response
    return {
      success: true,
      message: 'Activity log saved successfully',
      activity: {
        id: activity.id,
        activity_type: activity.activity_type,
        activity_time: activity.activity_time,
        details: activity.details,
        status: activity.status,
        ip_address: activity.ip_address,
        user_agent: activity.user_agent,
        unit_id: activity.unit_id,
        source: activity.source
      }
    };
  } catch (error) {
    console.error('Error saving activity log:', error);
    return {
      success: false,
      message: 'Failed to save activity log',
      activity: null
    };
  }
};


const saveConsent = async (consentInput, { auth }) => {
  try {
    const userId = auth?.userId;
    if (!userId) throw new Error('Unauthorized user');

    const mustBeSignedValue = consentInput.mustBeSigned;
    const mustBeSignedConverted = mustBeSignedValue === 'true' ? true : (mustBeSignedValue === 'false' ? false : null);

    const data = {
      unit_id: consentInput.unit_id,
      document_title: consentInput.document_title,
      document_type: consentInput.document_type || null,
      uploaded_document: null,  // As per your code; this is set to null intentionally
      must_be_signed: mustBeSignedConverted,
      notes: consentInput.notes || null,
      created_by: userId,
    };

    const result = await models.signConsentDocs.create(data);
    return result.id;
  } catch (error) {
    console.error('Error in save Consent resolver:', error.message);
    throw new Error(error.message);
  }
};

const updateConsent = async (consentUpdateInput, { auth }) => {
  const userId = auth?.userId;
  if (!userId) throw new Error('Unauthorized user');

  const existingConsent = await models.signConsentDocs.findByPk(consentUpdateInput.id);
  if (!existingConsent) throw new Error('Consent record not found');

  await existingConsent.update({
    document_title: consentUpdateInput.document_title,
    document_type: consentUpdateInput.document_type || null,
    uploaded_document: consentUpdateInput.uploaded_document || null,
    mustBeSigned: consentUpdateInput.mustBeSigned || null,
    notes: consentUpdateInput.notes || null,
    updated_by: userId,
  });

  return existingConsent.id;
};

const savepackage = async (packageInput, { auth }) => {
  try {
    if (!models?.package) {
      throw new Error('package model not found');
    }

    const userId = auth?.userId;
    if (!userId) throw new Error('Unauthorized user');

    const data = {
      name: packageInput.name,
      plan_type: packageInput.plan_type || null,
      max_employees: packageInput.maxEmployees || 0,
      max_storage_size: packageInput.maxStorageSize || 0,
      storage_unit: packageInput.storage_unit || 'mb',
      sort: packageInput.position?.toString() || '0',
      is_private: packageInput.isPrivate ? 1 : 0,
      is_recommended: packageInput.isRecommended ? 1 : 0,
      monthly_price: packageInput.hasMonthlyPlan ? packageInput.monthlyPrice || 0 : 0,
      annual_price: packageInput.hasAnnualPlan ? packageInput.annualPrice || 0 : 0,
      module_in_package: packageInput.modules ? JSON.stringify(packageInput.modules) : '[]',
      description: packageInput.description || '',
      unit_id: packageInput.unit_id || '',
      created_by: userId,
    };

    if (packageInput.currency) {
      const currency = await models.global_currency.findOne({
        where: { currency_code: packageInput.currency }
      });

      data.currency_id = currency ? currency.id : null;
    }

    const result = await models.package.create(data);

    console.log('package created:', result.toJSON());
    return true;
  } catch (error) {
    console.error('Error in save package:', error.message);
    throw new Error(error.message);
  }
};

const saveclient = async (clientInput, { auth }) => {
  try {
    if (!models?.client) throw new Error('client model not found');
    if (!auth?.userId) throw new Error('Unauthorized user');

    const userId = auth.userId;

    const clientData = {
      first_name: clientInput.first_name,
      last_name: clientInput.last_name,
      ssn: clientInput.ssn || null,
      id_type: clientInput.id_type || null,
      id_number: clientInput.id_number || null,
      phone: clientInput.phone || null,
      email: clientInput.email || null,
      gender: clientInput.gender || null,
      date_of_birth: clientInput.date_of_birth || null,
      opening_balance: clientInput.opening_balance || 0,
      monthly_gross_income: clientInput.monthly_gross_income || 0,
      additional_income: clientInput.additional_income || 0,
      marital_status: clientInput.marital_status || null,
      ethnicity: clientInput.ethnicity || null,
      corporation_name: clientInput.corporation_name || null,
      ein: clientInput.ein || null,
      street_number: clientInput.street_number || null,
      suite_floor: clientInput.suite_floor || null,
      zip_code: clientInput.zip_code || null,
      city: clientInput.city || null,
      state: clientInput.state || null,
      country: clientInput.country || null,
      mailing_address: clientInput.mailing_address || null,
      notes: clientInput.notes || null,
      status: clientInput.status || 'active',
      unit_id: clientInput.unit_id,
      created_by: userId,
    };

    const clientResult = await models.client.create(clientData);
    const clientId = clientResult.id;

    console.log('Client saved:', clientResult.toJSON ? clientResult.toJSON() : clientResult);

    // Step 2: Save client entity
    if (!models?.client_entity) throw new Error('client_entity model not found');

    const entityData = {
      client_id: clientId,
      entity_name: clientInput.entity_name,
      entity_ein: clientInput.entity_ein || null,
      email: clientInput.entity_email || null,
      phone: clientInput.entity_phone || '',
      service_id: clientInput.service_id || '',
      street_number: clientInput.entity_street_number || null,
      suite_floor: clientInput.entity_suite_floor || null,
      zip_code: clientInput.entity_zip_code || null,
      city: clientInput.entity_city || null,
      state: clientInput.entity_state || null,
      country: clientInput.entity_country || null,
      created_by: userId,
    };

    const entityResult = await models.client_entity.create(entityData);
    console.log(
      'Client entity saved:',
      entityResult.toJSON ? entityResult.toJSON() : entityResult
    );


    return clientId;
  } catch (error) {
    console.error('Error in save Client:', error.message);
    throw new Error(error.message);
  }
};

const saveClientEntity = async (entitiesInput, { auth }) => {
  try {
    if (!models?.client_entity) {
      throw new Error('client_entity model not found');
    }

    const userId = auth?.userId;
    if (!userId) throw new Error('Unauthorized user');

    const data = {
      client_id: entitiesInput.client_id || null,
      entity_name: entitiesInput.entity_name,
      entity_ein: entitiesInput.entity_ein || null,
      email: entitiesInput.email || null,
      service_id: entitiesInput.service_id || '',
      phone: entitiesInput.phone,
      street_number: entitiesInput.street_number || null,
      suite_floor: entitiesInput.suite_floor || null,
      zip_code: entitiesInput.zip_code || null,
      city: entitiesInput.city || null,
      state: entitiesInput.state || null,
      country: entitiesInput.country || null,
      created_by: userId,
    };

    let result;
    if (entitiesInput.id) {
      // Update existing entity
      await models.client_entity.update(data, {
        where: { id: entitiesInput.id },
      });
      result = await models.client_entity.findByPk(entitiesInput.id);
    } else {
      // Create new entity
      result = await models.client_entity.create(data);
    }

    console.log('client_entity saved:', result.toJSON ? result.toJSON() : result);
    return result.id; // return only ID as per schema
  } catch (error) {
    console.error('Error in save Client Entity:', error.message);
    throw new Error(error.message);
  }
};

const updateClientEntity = async (entitiesUpdateInput, { auth }) => {
  try {
    if (!models?.client_entity) {
      throw new Error("client_entity model not found")
    }

    const userId = auth?.userId
    if (!userId) throw new Error("Unauthorized user")

    const entityId = entitiesUpdateInput.id
    if (!entityId) throw new Error("Entity ID required for update")

    const data = {
      client_id: entitiesUpdateInput.client_id || null,
      entity_name: entitiesUpdateInput.entity_name,
      entity_ein: entitiesUpdateInput.entity_ein || null,
      email: entitiesUpdateInput.email || null,
      phone: entitiesUpdateInput.phone,
      service_id: entitiesUpdateInput.service_id || '',
      street_number: entitiesUpdateInput.street_number || null,
      suite_floor: entitiesUpdateInput.suite_floor || null,
      zip_code: entitiesUpdateInput.zip_code || null,
      city: entitiesUpdateInput.city || null,
      state: entitiesUpdateInput.state || null,
      country: entitiesUpdateInput.country || null,
      updated_by: userId,
    }

    const [affected] = await models.client_entity.update(data, {
      where: { id: entityId },
    })

    if (affected === 0) throw new Error("Entity not found or no changes applied")

    console.log("client_entity updated:", entityId)
    return true
  } catch (error) {
    console.error("Error in updateClientEntity:", error.message)
    throw new Error(error.message)
  }
};

const updateClientService = async (serviceUpdateInput, { auth }) => {
  try {
    if (!models?.client_service) {
      throw new Error("client_service model not found")
    }

    const userId = auth?.userId
    if (!userId) throw new Error("Unauthorized user")

    const serviceId = serviceUpdateInput.id
    if (!serviceId) throw new Error("Service ID required for update")

    const data = {
      client_id: serviceUpdateInput.client_id || null,
      code: serviceUpdateInput.code || null,
      name: serviceUpdateInput.name,
      price: serviceUpdateInput.price || null,
      status: serviceUpdateInput.status,
      description: serviceUpdateInput.description || null,
      updated_by: userId,
    }

    const [affected] = await models.client_service.update(data, {
      where: { id: serviceId },
    })

    if (affected === 0) throw new Error("Service not found or no changes applied")

    console.log("client_service updated:", serviceId)
    return true
  } catch (error) {
    console.error("Error in update Client Service:", error.message)
    throw new Error(error.message)
  }
};

const saveServiceEntry = async (serviceInput, { auth }) => {
  try {
    if (!models?.client_service) {
      throw new Error('client service model not found');
    }

    const userId = auth?.userId;
    if (!userId) throw new Error('Unauthorized user');

    const data = {
      unit_id: serviceInput.unit_id,
      code: serviceInput.code,
      name: serviceInput.name || null,
      price: serviceInput.price,
      status: serviceInput.status,
      description: serviceInput.description || null,
      created_by: userId,
    };

    let result;
    if (serviceInput.id) {
      await models.client_service.update(data, {
        where: { id: serviceInput.id },
      });
      result = await models.client_service.findByPk(serviceInput.id);
    } else {
      result = await models.client_service.create(data);
    }

    console.log('client_service saved:', result.toJSON ? result.toJSON() : result);
    return result.id;
  } catch (error) {
    console.error('Error in save ClientService:', error.message);
    throw new Error(error.message);
  }
};

const SaveEmployeeTasks = async (employee_taskInput, { auth }) => {
  try {
    const userId = auth?.userId;
    if (!userId) throw new Error('Unauthorized user');

    const employeeIds = Array.isArray(employee_taskInput.team)
      ? employee_taskInput.team
      : [];

    const taskData = {
      title: employee_taskInput.title,
      category: employee_taskInput.category,
      project: employee_taskInput.project,
      start_date: employee_taskInput.start_date,
      end_date: employee_taskInput.end_date,
      estimated_hours: employee_taskInput.estimated_hours,
      status: employee_taskInput.status || 'Incomplete',
      description: employee_taskInput.description,
      unit_id: employee_taskInput.unit_id,
      created_by: userId,
      created_at: new Date(),
      updated_at: new Date(),
    };

    const task = await models.tasks.create(taskData);
    console.log('Task created:', task.toJSON ? task.toJSON() : task);

    if (employeeIds.length > 0) {
      const taskEmployees = employeeIds.map(empId => ({
        task_id: task.id,
        employee_id: empId,
        created_at: new Date(),
        updated_at: new Date(),
      }));

      await models.task_employee.bulkCreate(taskEmployees);
      console.log(' Task employees linked:', taskEmployees);
    }

    return task.id;

  } catch (error) {
    console.error('Error saving employee task:', error.message);
    throw new Error(error.message);
  }
};

const SaveTaskHistory = async (task_history_input, { auth }) => {
  try {
    const userId = auth?.userId;
    if (!userId) throw new Error('Unauthorized user');

    // Prepare task history data based on the input
    const data = {
      unit_id: task_history_input.unit_id,
      task_id: task_history_input.task_id,
      sub_task_id: task_history_input.sub_task_id || null,
      user_id: task_history_input.user_id,
      details: task_history_input.details || null,
      created_by: task_history_input.created_by,
      created_at: new Date(),
      updated_at: new Date(),
    };

    // Create the task history record
    const taskHistory = await models.task_history.create(data);

    return true; // Return true to indicate success
  } catch (error) {
    console.error('Error saving task history:', error.message);
    throw new Error(error.message);
  }
};

const SaveSubTask = async (subTaskInput, { auth }) => {
  try {
    const userId = auth?.userId;
    if (!userId) throw new Error('Unauthorized user');

    const {
      title,
      start_date,
      due_date,
      description,
      status,
      task_id,
      assigned_to,
      assigned_by,
      unit_id,
    } = subTaskInput;

    const subTaskData = {
      title,
      start_date,
      due_date,
      description,
      status: status || 'Pending',
      task_id,
      assigned_to,
      assigned_by,
      unit_id,
      created_by: userId,
      created_at: new Date(),
      updated_at: new Date(),
    };

    const subTask = await models.sub_tasks.create(subTaskData);
    console.log('Subtask created:', subTask.toJSON ? subTask.toJSON() : subTask);

    return true;
  } catch (error) {
    console.error('Error saving subtask:', error.message);
    throw new Error(error.message);
  }
};

const SaveTaskComment = async (taskCommentInput, { auth }) => {
  try {
    const userId = auth?.userId
    if (!userId) throw new Error('Unauthorized user')

    const { comment, assigned_by, unit_id, task_id } = taskCommentInput

    if (!comment || !assigned_by) {
      throw new Error('Comment text and assigned_by are required')
    }

    const commentData = {
      comment,
      assigned_by,
      unit_id,
      task_id,
      created_by: userId,
      created_at: new Date(),
      updated_at: new Date(),
    }

    const savedComment = await models.task_comments.create(commentData)

    console.log('Task comment saved:', savedComment.toJSON ? savedComment.toJSON() : savedComment)

    return true
  } catch (error) {
    console.error('Error saving task comment:', error.message)
    throw new Error(error.message)
  }
}

const SaveTaskNote = async (taskNoteInput, { auth }) => {
  try {
    const userId = auth?.userId;
    if (!userId) throw new Error('Unauthorized user');

    const { notes, assigned_by, unit_id, task_id } = taskNoteInput;

    // Validate required fields
    if (!notes || !assigned_by || !task_id) {
      throw new Error('Notes, assigned_by, and task_id are required');
    }

    const noteData = {
      notes, // Maps to 'notes' column in the table schema
      assigned_by,
      unit_id, // Optional, can be null
      task_id,
      created_by: userId,
      created_at: new Date(),
      updated_at: new Date(),
    };

    const savedNote = await models.task_notes.create(noteData);

    console.log('Task note saved:', savedNote.toJSON());

    return true;
  } catch (error) {
    console.error('Error saving task note:', error.message);
    throw new Error(`Failed to save task note: ${error.message}`);
  }
};

const ReactToComment = async (reactToCommentInput, { auth }) => {
  try {
    const userId = auth?.userId || reactToCommentInput.user_id;
    if (!userId) throw new Error('Unauthorized: user ID missing');

    const { comment_id, emoji_name, user_id, task_id, unit_id } = reactToCommentInput;

    if (!comment_id || !user_id || !task_id) {
      throw new Error('comment_id, user_id, and task_id are required');
    }

    const comment = await models.task_comments.findOne({ where: { id: comment_id, task_id } });
    if (!comment) throw new Error('Comment not found or does not belong to task');

    const existingReaction = await models.task_comment_emoji.findOne({
      where: {
        comment_id,
        user_id: userId
      }
    });

    if (existingReaction) {
      if (existingReaction.emoji_name === emoji_name) {
        await models.task_comment_emoji.destroy({
          where: {
            comment_id,
            user_id: userId,
          },
        });
      } else {
        await models.task_comment_emoji.update(
          {
            emoji_name,
            updated_at: new Date(),
          },
          {
            where: {
              comment_id,
              user_id: userId,
            },
          }
        );
      }
    } else {
      await models.task_comment_emoji.create({
        comment_id,
        user_id: userId,
        emoji_name,
        task_id,
        unit_id,
        created_by: user_id,
        updated_at: new Date(),
      });
    }

    const likes = await models.task_comment_emoji.count({
      where: { comment_id, emoji_name: 'thumbs-up' }
    });
    const dislikes = await models.task_comment_emoji.count({
      where: { comment_id, emoji_name: 'thumbs-down' }
    });

    await models.task_comments.update(
      { likes, dislikes },
      { where: { id: comment_id } }
    );

    return true;
  } catch (error) {
    console.error('react To Comment error:', error.message);
    throw new Error(`Failed to react to comment: ${error.message}`);
  }
};

const RemoveCommentReaction = async (_, { comment_id, user_id }, { auth }) => {
  try {
    const userId = auth?.userId || user_id;
    if (!userId) throw new Error('Unauthorized');

    if (!comment_id || !user_id) {
      throw new Error('comment_id and user_id are required');
    }

    const comment = await models.task_comments.findOne({
      where: { id: comment_id },
      attributes: ['id', 'task_id'],
    });

    if (!comment) throw new Error('Comment not found');

    await models.task_comment_emoji.destroy({
      where: {
        comment_id,
        user_id: userId,
      },
    });

    const likes = await models.task_comment_emoji.count({
      where: { comment_id, emoji_name: 'thumbs-up' },
    });
    const dislikes = await models.task_comment_emoji.count({
      where: { comment_id, emoji_name: 'thumbs-down' },
    });

    await models.task_comments.update(
      { likes, dislikes },
      { where: { id: comment_id } }
    );

    return true;
  } catch (error) {
    console.error('remove Comment Reaction error:', error.message);
    throw new Error(`Failed to remove reaction: ${error.message}`);
  }
};

const SaveTimeSheet = async (timeSheetInput, { auth }) => {
  try {
    const userId = auth?.userId;
    if (!userId) throw new Error('Unauthorized user');

    const {
      user_id,
      start_time,
      end_time,
      total_time,
      memo,
      task_id,
      project_id,
      unit_id,
    } = timeSheetInput;

    console.log('Received timeSheetInput:', JSON.stringify(timeSheetInput, null, 2));

    const formatDate = (dateInput, fieldName) => {
      if (!dateInput && fieldName === 'start_time') {
        throw new Error(`Date input is missing for ${fieldName}`);
      }
      if (!dateInput) return null;

      let date;
      if (typeof dateInput === 'string') {
        const regex = /^(\d{2})-(\d{2})-(\d{4}) (\d{1,2}):(\d{2}) (am|pm)$/i;
        const match = dateInput.match(regex);
        if (match) {
          let [, day, month, year, hours, minutes, period] = match;
          hours = parseInt(hours, 10);
          if (period.toLowerCase() === 'pm' && hours < 12) hours += 12;
          if (period.toLowerCase() === 'am' && hours === 12) hours = 0;
          date = new Date(`${year}-${month}-${day}T${hours.toString().padStart(2, '0')}:${minutes}:00`);
        } else {
          date = new Date(dateInput);
        }
      } else if (dateInput instanceof Date) {
        date = dateInput;
      } else {
        throw new Error(`Invalid type for ${fieldName}: ${typeof dateInput}`);
      }

      if (isNaN(date.getTime())) {
        throw new Error(`Invalid date format for ${fieldName}: ${dateInput}`);
      }

      return date.toISOString().slice(0, 19).replace('T', ' ');
    };

    const formattedStartTime = formatDate(start_time, 'start_time');
    const formattedEndTime = formatDate(end_time, 'end_time');

    if (end_time && new Date(formattedStartTime) > new Date(formattedEndTime)) {
      throw new Error('start_time cannot be later than end_time');
    }

    const TimeSheetData = {
      user_id,
      start_time: formattedStartTime,
      end_time: formattedEndTime,
      total_time,
      memo,
      task_id,
      project_id,
      unit_id,
      created_by: userId,
      created_at: new Date().toISOString().slice(0, 19).replace('T', ' '),
      updated_at: new Date().toISOString().slice(0, 19).replace('T', ' '),
    };

    console.log('Saving TimeSheetData:', JSON.stringify(TimeSheetData, null, 2));

    const timesheet = await models.project_time_logs.create(TimeSheetData);
    return timesheet.id; // Return the created timesheet ID
  } catch (error) {
    console.error('Error saving timesheet:', error.message, error.stack);
    throw new Error(`[GraphQL] Failed to save timesheet: ${error.message}`);
  }
};

const UpdateTimeSheet = async (timeSheetInput, { auth }) => {
  try {
    const userId = auth?.userId;
    if (!userId) throw new Error('Unauthorized user');

    const {
      id,
      user_id,
      start_time,
      end_time,
      total_time,
      memo,
      task_id,
      project_id,
      unit_id,
    } = timeSheetInput;

    if (!id) throw new Error('Timesheet ID is required for update');

    console.log('Received timeSheetInput for update:', JSON.stringify(timeSheetInput, null, 2));

    const formatDate = (dateInput, fieldName) => {
      if (!dateInput && fieldName === 'start_time') {
        throw new Error(`Date input is missing for ${fieldName}`);
      }
      if (!dateInput) return null;

      let date;
      if (typeof dateInput === 'string') {
        const regex = /^(\d{2})-(\d{2})-(\d{4}) (\d{1,2}):(\d{2}) (am|pm)$/i;
        const match = dateInput.match(regex);
        if (match) {
          let [, day, month, year, hours, minutes, period] = match;
          hours = parseInt(hours, 10);
          if (period.toLowerCase() === 'pm' && hours < 12) hours += 12;
          if (period.toLowerCase() === 'am' && hours === 12) hours = 0;
          date = new Date(`${year}-${month}-${day}T${hours.toString().padStart(2, '0')}:${minutes}:00`);
        } else {
          date = new Date(dateInput);
        }
      } else if (dateInput instanceof Date) {
        date = dateInput;
      } else {
        throw new Error(`Invalid type for ${fieldName}: ${typeof dateInput}`);
      }

      if (isNaN(date.getTime())) {
        throw new Error(`Invalid date format for ${fieldName}: ${dateInput}`);
      }

      return date.toISOString().slice(0, 19).replace('T', ' ');
    };

    const formattedStartTime = formatDate(start_time, 'start_time');
    const formattedEndTime = formatDate(end_time, 'end_time');

    if (end_time && new Date(formattedStartTime) > new Date(formattedEndTime)) {
      throw new Error('start_time cannot be later than end_time');
    }

    const TimeSheetData = {
      user_id,
      start_time: formattedStartTime,
      end_time: formattedEndTime,
      total_time,
      memo,
      task_id,
      project_id,
      unit_id,
      updated_at: new Date().toISOString().slice(0, 19).replace('T', ' '),
    };

    console.log('Updating TimeSheetData:', JSON.stringify(TimeSheetData, null, 2));

    await models.project_time_logs.update(TimeSheetData, {
      where: { id },
    });

    return true;
  } catch (error) {
    console.error('Error updating timesheet:', error.message, error.stack);
    throw new Error(`[GraphQL] Failed to update timesheet: ${error.message}`);
  }
};

const saveVendor = async (vendorInput, { auth }) => {

  const transaction = await models.sequelize.transaction();
  try {
    if (!models?.vendor) throw new Error('Vendor model not found');
    if (!models?.vendor_payment) throw new Error('VendorPayment model not found');
    if (!models?.vendor_tax) throw new Error('VendorTax model not found');

    const userId = auth?.userId;
    if (!userId) throw new Error('Unauthorized user');

    // 1. Create vendor (core details)
    const vendor = await models.vendor.create(
      {
        vendor_name: vendorInput.vendor_name,
        opening_balance: vendorInput.opening_balance ?? 0,
        as_of_date: vendorInput.as_of_date ?? null,
        date_of_birth: vendorInput.date_of_birth ?? null,
        company_name: vendorInput.company_name ?? null,
        name_prefix: vendorInput.name_prefix ?? null,
        first_name: vendorInput.first_name ?? null,
        m_i: vendorInput.m_i ?? null,
        last_name: vendorInput.last_name ?? null,
        job_title: vendorInput.job_title ?? null,
        phone: vendorInput.phone ?? null,
        work_phone: vendorInput.work_phone ?? null,
        mobile: vendorInput.mobile ?? null,
        fax: vendorInput.fax ?? null,
        email: vendorInput.email ?? null,
        cc_email: vendorInput.cc_email ?? null,
        website: vendorInput.website ?? null,
        otherDesc: vendorInput.otherDesc ?? null,
        billed_street: vendorInput.billed_street ?? null,
        billed_suite: vendorInput.billed_suite ?? null,
        billed_zip: vendorInput.billed_zip ?? null,
        billed_city: vendorInput.billed_city ?? null,
        billed_state: vendorInput.billed_state ?? null,
        shipped_street: vendorInput.shipped_street ?? null,
        shipped_suite: vendorInput.shipped_suite ?? null,
        shipped_zip: vendorInput.shipped_zip ?? null,
        shipped_city: vendorInput.shipped_city ?? null,
        shipped_state: vendorInput.shipped_state ?? null,
        vendor_type_id: vendorInput.vendor_type_id ?? null,
        unit_id: vendorInput.unit_id ?? null,
        is_inactive: vendorInput.is_inactive ?? false,
        created_by: userId,
      },
      { transaction }
    );

    // 2. Create vendor payments (only if any payment info is provided)
    if (vendorInput.account_no) {
      await models.vendor_payment.create(
        {
          vendor_id: vendor.id,
          account_no: vendorInput.account_no ?? null,
          credit_limit: vendorInput.credit_limit ?? null,
          print_name_on_check_as: vendorInput.print_name_on_check ?? null,
          payment_terms_id: vendorInput.payment_terms_id ?? null,
          created_by: userId,
        },
        { transaction }
      );
    }

    // 3. Create vendor tax info (only if tax data is provided)
    if (vendorInput.tax_id) {
      await models.vendor_tax.create(
        {
          vendor_id: vendor.id,
          tax_id: vendorInput.tax_id ?? null,
          is_1099_eligible: vendorInput.is_1099_eligible ?? false,
          created_by: userId,
        },
        { transaction }
      );
    }

    // Commit transaction
    await transaction.commit();

    console.log('Vendor saved:', vendor.toJSON ? vendor.toJSON() : vendor);

    return vendor.id;
  } catch (error) {
    await transaction.rollback();
    console.error('Error in save vendor:', error.message);
    throw new Error(error.message);
  }
};

const saveVendorPayment = async (vendorPaymentInput, { auth }) => {
  try {
    if (!models?.vendor_payment) throw new Error("vendor_payment model not found");

    const userId = auth?.userId;
    if (!userId) throw new Error("Unauthorized user");

    const data = {
      account_no: vendorPaymentInput.account_no,
      vendor_id: vendorPaymentInput.vendor_id,
      credit_limit: vendorPaymentInput.credit_limit || null,
      print_name_on_check_as: vendorPaymentInput.print_name_on_check_as || null,
      payment_terms_id: vendorPaymentInput.payment_terms_id || null,
      created_by: userId,
    };

    const result = await models.vendor_payment.create(data);

    console.log("Vendor payment saved:", result.toJSON ? result.toJSON() : result);

    return result; // full object (matches schema)
  } catch (error) {
    console.error("Error in save vendor payment:", error.message);
    throw new Error(error.message);
  }
};


const updateVendorPayment = async (vendorPaymentUpdateInput, { auth }) => {
  try {
    if (!models?.vendor_payment) throw new Error("vendor_payment model not found");

    const userId = auth?.userId;
    if (!userId) throw new Error("Unauthorized user");

    if (!vendorPaymentUpdateInput.id) {
      throw new Error("vendor_payment id is required for update");
    }

    const data = {
      account_no: vendorPaymentUpdateInput.account_no,
      vendor_id: vendorPaymentUpdateInput.vendor_id,
      credit_limit: vendorPaymentUpdateInput.credit_limit || null,
      print_name_on_check_as: vendorPaymentUpdateInput.print_name_on_check_as || null,
      payment_terms_id: vendorPaymentUpdateInput.payment_terms_id || null,
      updated_by: userId,
    };

    const [affectedRows] = await models.vendor_payment.update(data, {
      where: { id: vendorPaymentUpdateInput.id },
    });

    if (affectedRows === 0) {
      return false; // nothing updated
    }

    console.log("Vendor payment updated successfully:", vendorPaymentUpdateInput.id);
    return true;
  } catch (error) {
    console.error("Error in update vendor payment:", error.message);
    return false;
  }
};

const updateVendorTax = async (vendorTaxUpdateInput, { auth }) => {
  try {
    if (!models?.vendor_tax) throw new Error("vendor_tax model not found");

    const userId = auth?.userId;
    if (!userId) throw new Error("Unauthorized user");

    // If updating an existing record, include id
    const whereClause = vendorTaxUpdateInput.id
      ? { id: vendorTaxUpdateInput.id }
      : { vendor_id: vendorTaxUpdateInput.vendor_id };

    const data = {
      vendor_id: vendorTaxUpdateInput.vendor_id,
      tax_id: vendorTaxUpdateInput.tax_id || null,
      is_1099_eligible: vendorTaxUpdateInput.is_1099_eligible || null,
      updated_by: userId,
    };

    const [affectedRows] = await models.vendor_tax.update(data, {
      where: whereClause,
    });

    if (affectedRows === 0) {
      return false; // nothing updated
    }

    console.log("Vendor tax updated successfully:", vendorTaxUpdateInput.id || vendorTaxUpdateInput.vendor_id);
    return true;
  } catch (error) {
    console.error("Error in update vendor tax:", error.message);
    return false;
  }
};

const updateExpenseType = async (expenseTypeUpdateInput, { auth }) => {
  try {
    if (!models?.ExpenseType) {
      throw new Error("ExpenseType model not found");
    }

    const userId = auth?.userId;
    if (!userId) throw new Error("Unauthorized user");

    const { id, type_name, type_date } = expenseTypeUpdateInput;

    if (!id) {
      throw new Error("Expense Type ID is required for update");
    }

    const data = {
      type_name,
      type_date,
      updated_by: userId,
    };

    const [affectedRows] = await models.ExpenseType.update(data, {
      where: { id },
    });

    if (affectedRows === 0) {
      console.log("No expense type found to update with ID:", id);
      return false;
    }

    console.log("Expense type updated successfully:", id);
    return true;
  } catch (error) {
    console.error("Error in update Expense Type:", error.message);
    return false;
  }
};

const updateExpense = async (expensesInput, { auth }) => {
  try {
    if (!models?.expenses) {
      throw new Error("expenses model not found");
    }

    const userId = auth?.userId;
    if (!userId) throw new Error("Unauthorized user");

    const {
      id,
      expense_name,
      expense_type_id,
      description,
      expense_amount,
      expense_date,
      status
    } = expensesInput;

    if (!id) {
      throw new Error("Expense ID is required for update");
    }

    // Prepare data for update
    const data = {
      expense_name,
      expense_type_id,
      description,
      expense_amount,
      expense_date,
      status,
      updated_by: userId
    };

    // Perform update
    const [affectedRows] = await models.expenses.update(data, {
      where: { id },
    });

    if (affectedRows === 0) {
      console.log("No expense found to update with ID:", id);
      return false;
    }

    console.log("Expense updated successfully:", id);
    return true;
  } catch (error) {
    console.error("Error in updateExpense:", error.message);
    return false;
  }
};




const updateChartAccount = async (chartAccountUpdateInput, { auth }) => {
  try {
    if (!models?.chart_of_account) {
      throw new Error("chart of account model not found");
    }

    const userId = auth?.userId;
    if (!userId) throw new Error("Unauthorized user");

    if (!chartAccountUpdateInput.id) {
      throw new Error("Chart Account ID is required for update");
    }

    const data = {
      type_id: chartAccountUpdateInput.type_id,
      account: chartAccountUpdateInput.account,
      description: chartAccountUpdateInput.description,
      sub_account_of: chartAccountUpdateInput.sub_account_of,
      account_no: chartAccountUpdateInput.account_no,
      routing_no: chartAccountUpdateInput.routing_no,
      check_no: chartAccountUpdateInput.check_no,
      opening_balance: chartAccountUpdateInput.opening_balance,
      tax_line_map: chartAccountUpdateInput.tax_line_map,
      note: chartAccountUpdateInput.note,
      unit_id: chartAccountUpdateInput.unit_id,
      created_by: userId,

    };

    // Perform update
    const [affectedRows] = await models.chart_of_account.update(data, {
      where: { id: chartAccountUpdateInput.id },
    });

    if (affectedRows === 0) {
      console.log("No chart account found to update with ID:", chartAccountUpdateInput.id);
      return false;
    }

    console.log("Chart account updated successfully:", chartAccountUpdateInput.id);
    return true;
  } catch (error) {
    console.error("Error in update chart account:", error.message);
    return false;
  }
};

const saveVendorType = async (vendorTypeInput, { auth }) => {
  try {
    if (!models?.vendor_type) {
      throw new Error('Vendor Type model not found')
    }


    const userId = auth?.userId;
    if (!userId) throw new Error('Unauthorized user');

    const data = {
      vendor_title: vendorTypeInput.vendor_title,
      unit_id: vendorTypeInput.unit_id,
      vendor_parent: vendorTypeInput.vendor_parent || null,
      status: vendorTypeInput.status || 'active',
      created_by: userId,
    };

    const result = await models.vendor_type.create(data)
    console.log('Vendor Type saved:', result.toJSON ? result.toJSON() : result);

    return true;
  } catch (error) {
    console.error('Error in save Vendor Type:', error.message);
    throw new Error(error.message);
  }
};

const addPaymentTerm = async (paymentTermInput, { auth }) => {
  try {
    if (!models?.payment_term) {
      throw new Error("payment_term model not found");
    }

    const userId = auth?.userId;
    if (!userId) throw new Error("Unauthorized user");

    const data = {
      term_name: paymentTermInput.term_name,
      term_type: paymentTermInput.term_type,
      is_inactive: paymentTermInput.is_inactive ?? false,

      // Standard fields
      net_due_days: paymentTermInput.net_due_days ?? null,
      discount_percent: paymentTermInput.discount_percent ?? null,
      discount_if_paid_within_days: paymentTermInput.discount_if_paid_within_days ?? null,

      // Date-driven fields
      net_due_day_of_month: paymentTermInput.net_due_day_of_month ?? null,
      due_next_month_if_within_days: paymentTermInput.due_next_month_if_within_days ?? null,
      date_driven_discount_percent: paymentTermInput.date_driven_discount_percent ?? null,
      discount_if_paid_before_day: paymentTermInput.discount_if_paid_before_day ?? null,

      created_by: userId
    };

    const result = await models.payment_term.create(data);
    return result; // Sequelize object maps to PaymentTerm type
  } catch (error) {
    console.error("Error in addPaymentTerm:", error.message);
    throw new Error(error.message);
  }
};

const saveChartAccount = async (chartAccountInput, { auth }) => {
  try {
    if (!models?.chart_of_account) {
      throw new Error("chart of account model not found");
    }

    const userId = auth?.userId;
    if (!userId) throw new Error("Unauthorized user");

    const data = {
      type_id: chartAccountInput.type_id,
      account: chartAccountInput.account,
      description: chartAccountInput.description,
      sub_account_of: chartAccountInput.sub_account_of,
      account_no: chartAccountInput.account_no,
      routing_no: chartAccountInput.routing_no,
      check_no: chartAccountInput.check_no,
      opening_balance: chartAccountInput.opening_balance,
      tax_line_map: chartAccountInput.tax_line_map,
      note: chartAccountInput.note,
      unit_id: chartAccountInput.unit_id,
      created_by: userId,
    };

    const result = await models.chart_of_account.create(data);
    return result;
  } catch (error) {
    console.error("Error in chart of account:", error.message);
    throw new Error(error.message);
  }
};

const changePassword = async (changePasswordInput, { auth }) => {
  try {
    if (!models?.user) {
      throw new Error("User model not found");
    }

    const { email, newPassword, user_pass } = changePasswordInput;

    if (!email || !newPassword || !user_pass) {
      throw new Error("Email, new password (hashed), and user_pass are required");
    }

    // Find user by email
    const user = await models.user.findOne({ where: { email } });
    if (!user) {
      throw new Error("User not found with this email");
    }

    // Update user password fields
    await user.update({
      password: newPassword, // hashed password
      user_pass: user_pass,  // plain/original password
    });

    return {
      success: true,
      message: "Password updated successfully",
    };
  } catch (error) {
    console.error("Error in changePassword:", error.message);
    throw new Error(error.message);
  }
};

const resetPassword = async (resetPasswordInput, { auth }) => {
  try {
    if (!models?.user) {
      throw new Error("User model not found");
    }

    const { email, new_password, user_pass } = resetPasswordInput;

    if (!email || !new_password || !user_pass) {
      throw new Error("Email, new password (hashed), and user_pass are required");
    }

    // Find user by email
    const user = await models.user.findOne({ where: { email } });
    if (!user) {
      throw new Error("User not found with this email");
    }

    // Update user password fields
    await user.update({
      password: new_password, // hashed password
      user_pass: user_pass,  // plain/original password
    });

    return {
      success: true,
      message: "Password Reset Successfully",
    };
  } catch (error) {
    console.error("Error in Reset Password:", error.message);
    throw new Error(error.message);
  }
};

const checkEmailExists = async (emailInput) => {
  try {
    if (!models?.user) {
      throw new Error("User model not found");
    }

    const email = emailInput?.email; // extract email from object

    if (!email) {
      return {
        success: false,
        message: "Email is required",
      };
    }

    // Find user by email
    const user = await models.user.findOne({ where: { email } });

    if (!user) {
      return {
        success: false,
        message: "User not found with this email",
      };
    }

    return {
      success: true,
      message: "User exists with this email",
    };
  } catch (error) {
    console.error("Error in checkEmailExists:", error.message);
    return {
      success: false,
      message: error.message,
    };
  }
};


const savecheck = async (checkpaymentinput, { auth }) => {
  try {
    if (!models?.checks) {
      throw new Error("Checks model not found");
    }

    const userId = auth?.userId;
    if (!userId) throw new Error("Unauthorized user");

    // Save main check
    const check = await models.checks.create({
      ...checkpaymentinput,
      created_by: userId,
    });

    if (check) {

    }

    if (checkpaymentinput.bank_id) {
      const bank = await models.NewBank.findByPk(checkpaymentinput.bank_id);
      console.log("fetched bank", bank)
      if (bank) {
        const nextCheckNo = String(parseInt(bank.check_no || "0") + 1).padStart(5, "0");
        await bank.update({ check_no: nextCheckNo });
      }
    }

    let items = [];
    if (checkpaymentinput.items?.length) {
      const itemsData = checkpaymentinput.items.map((item) => ({
        ...item,
        check_id: check.id,
      }));
      items = await models.check_items.bulkCreate(itemsData, { returning: true });
    }

    const fullCheck = await models.checks.findOne({
      where: { id: check.id },
      include: [
        {
          model: models.check_items,
          as: 'items'
        },
        {
          model: models.vendor,
          as: 'vendor',
          attributes: [
            'id',
            'vendor_name',
            'email',
            'billed_street',
            'billed_suite',
            'billed_zip',
            'billed_city',
            'billed_state'
          ]
        },
        {
          model: models.NewBank,
          as: 'bank',
          attributes: [
            'id',
            'name',
            'account_name',
            'account_no',
            'routing_no',
            'street_no',
            'city',
            'state',
            'zip_code'
          ]
        }
      ]
    });

    if (!fullCheck) {
      throw new Error("Failed to fetch saved check");
    }

    return {
      id: fullCheck.id,
      vendor_id: fullCheck.vendor_id,
      vendor: fullCheck.vendor
        ? {
          id: fullCheck.vendor.id,
          vendor_name: fullCheck.vendor.vendor_name,
          email: fullCheck.vendor.email,
          billed_street: fullCheck.vendor.billed_street,
          billed_suite: fullCheck.vendor.billed_suite,
          billed_city: fullCheck.vendor.billed_city,
          billed_state: fullCheck.vendor.billed_state,
          billed_zip: fullCheck.vendor.billed_zip,
        }
        : null,
      bank_id: fullCheck.bank_id,
      bank: fullCheck.bank
        ? {
          id: fullCheck.bank.id,
          account_name: fullCheck.bank.account_name,
          account_no: fullCheck.bank.account_no,
          routing_no: fullCheck.bank.routing_no,
          name: fullCheck.bank.name,
          city: fullCheck.bank.city,
          street_no: fullCheck.bank.street_no,
          state: fullCheck.bank.state,
          zip_code: fullCheck.bank.zip_code,
        }
        : null,
      available_balance: fullCheck.available_balance,
      street: fullCheck.street,
      suit: fullCheck.suit,
      zip: fullCheck.zip,
      city: fullCheck.city,
      state: fullCheck.state,
      check_no: fullCheck.check_no,
      total_amount: fullCheck.total_amount,
      payment_date: fullCheck.payment_date,
      invoice_number: fullCheck.invoice_number,
      remaining_balance: fullCheck.remaining_balance,
      send_email: fullCheck.send_email,
      print_check: fullCheck.print_check,
      unit_id: fullCheck.unit_id,
      items: fullCheck.items.map((item) => ({
        account_id: item.account_id,
        memo: item.memo,
        amount: item.amount,
      })),
    };
  } catch (error) {
    console.error("Error in save check:", error);
    throw new Error(error.message);
  }
};

const updatecheck = async (checkpaymentUpdateInput, { auth }) => {
  try {
    if (!models?.checks) throw new Error("Checks model not found");
    const userId = auth?.userId;
    if (!userId) throw new Error("Unauthorized user");

    if (!checkpaymentUpdateInput.id) throw new Error("Check ID is required for update");

    await models.checks.update(
      { ...checkpaymentUpdateInput },
      { where: { id: checkpaymentUpdateInput.id } }
    );

    if (checkpaymentUpdateInput.items?.length) {
      await models.check_items.destroy({ where: { check_id: checkpaymentUpdateInput.id } });

      const itemsData = checkpaymentUpdateInput.items.map((item) => ({
        ...item,
        check_id: checkpaymentUpdateInput.id,
      }));
      await models.check_items.bulkCreate(itemsData);
    }

    const fullCheck = await models.checks.findOne({
      where: { id: checkpaymentUpdateInput.id },
      include: [
        { model: models.check_items, as: "items" },
        {
          model: models.vendor,
          as: "vendor",
          attributes: [
            "id",
            "vendor_name",
            "email",
            "billed_street",
            "billed_suite",
            "billed_zip",
            "billed_city",
            "billed_state",
          ],
        },
        {
          model: models.NewBank,
          as: "bank",
          attributes: [
            "id",
            "name",
            "account_name",
            "account_no",
            "routing_no",
            "street_no",
            "city",
            "state",
            "zip_code",
          ],
        },
      ],
    });

    if (!fullCheck) throw new Error("Failed to fetch updated check");


    return {
      id: fullCheck.id,
      vendor_id: fullCheck.vendor_id,
      vendor: fullCheck.vendor
        ? {
          id: fullCheck.vendor.id,
          vendor_name: fullCheck.vendor.vendor_name,
          email: fullCheck.vendor.email,
          billed_street: fullCheck.vendor.billed_street,
          billed_suite: fullCheck.vendor.billed_suite,
          billed_city: fullCheck.vendor.billed_city,
          billed_state: fullCheck.vendor.billed_state,
          billed_zip: fullCheck.vendor.billed_zip,
        }
        : null,
      bank_id: fullCheck.bank_id,
      bank: fullCheck.bank
        ? {
          id: fullCheck.bank.id,
          account_name: fullCheck.bank.account_name,
          account_no: fullCheck.bank.account_no,
          routing_no: fullCheck.bank.routing_no,
          name: fullCheck.bank.name,
          city: fullCheck.bank.city,
          street_no: fullCheck.bank.street_no,
          state: fullCheck.bank.state,
          zip_code: fullCheck.bank.zip_code,
        }
        : null,
      available_balance: fullCheck.available_balance,
      street: fullCheck.street,
      suit: fullCheck.suit,
      zip: fullCheck.zip,
      city: fullCheck.city,
      state: fullCheck.state,
      check_no: fullCheck.check_no,
      total_amount: fullCheck.total_amount,
      payment_date: fullCheck.payment_date,
      invoice_number: fullCheck.invoice_number,
      remaining_balance: fullCheck.remaining_balance,
      send_email: fullCheck.send_email,
      print_check: fullCheck.print_check,
      unit_id: fullCheck.unit_id,
      items: fullCheck.items.map((item) => ({
        account_id: item.account_id,
        memo: item.memo,
        amount: item.amount,
      })),
    };
  } catch (error) {
    console.error("Error in updatecheck:", error);
    throw new Error(error.message);
  }
};

const updateProject = async (projectUpdateInput, { auth }) => {
  try {
    const userId = auth?.userId;
    if (!userId) throw new Error('Unauthorized user');
    const { id, team, ...rest } = projectUpdateInput;
    const teamCsv = Array.isArray(team) ? team.join(',') : team;
    const [updatedRows] = await models.projects.update(
      {
        ...rest,
        team: teamCsv,
        updated_at: new Date(),
      },
      {
        where: { id },
      }
    );
    if (updatedRows === 0) {
      throw new Error('Project not found or nothing to update');
    }
    console.log(`Project ${id} updated successfully.`);
    return updatedRows;
  } catch (error) {
    console.error('Error updating project:', error.message);
    throw new Error(error.message);
  }
};

const updatetask = async (taskUpdateInput, { auth }) => {
  try {
    const userId = auth?.userId;
    if (!userId) throw new Error('Unauthorized user');

    const { id, team, ...rest } = taskUpdateInput;
    if (!id) throw new Error('Task ID is required');

    // Ensure task exists
    const existingTask = await models.tasks.findByPk(id);
    if (!existingTask) throw new Error('Task not found');

    // Convert team to array of employee IDs
    const employeeIds = Array.isArray(team) ? team : [];

    // Prepare updated task data
    const updatedTaskData = {
      ...rest,
      updated_at: new Date(),
      updated_by: userId,
    };

    // Update main task record
    await models.tasks.update(updatedTaskData, { where: { id } });
    console.log(`✅ Task ${id} updated successfully.`);

    // --- Manage team (task_employee table) ---
    if (employeeIds.length > 0) {
      // Remove existing team members
      await models.task_employee.destroy({ where: { task_id: id } });

      // Add updated team members
      const taskEmployees = employeeIds.map(empId => ({
        task_id: id,
        employee_id: empId,
        created_at: new Date(),
        updated_at: new Date(),
      }));

      await models.task_employee.bulkCreate(taskEmployees);
      console.log('👥 Task employees updated:', employeeIds);
    } else {
      // If no team provided, clear existing links
      await models.task_employee.destroy({ where: { task_id: id } });
      console.log('👥 Task team cleared');
    }

    return true;
  } catch (error) {
    console.error('❌ Error updating task:', error.message);
    throw new Error(error.message);
  }
};

const updateholiday = async (holidayUpdateInput, { auth }) => {
  try {
    const userId = auth?.userId;
    if (!userId) throw new Error('Unauthorized user');

    const { id, department, designation, employee_type, unit_id, repeats } = holidayUpdateInput;

    await models.holiday.update(
      {
        department: Array.isArray(department) ? department : [department],
        designation: Array.isArray(designation) ? designation : [designation],
        employee_type: Array.isArray(employee_type) ? employee_type : [employee_type],
        unit_id: unit_id || null,
        date: repeats?.[0]?.date || null,
        occasion: repeats?.[0]?.occasion || null,
        updated_at: new Date(),
        updated_by: userId
      },
      {
        where: { id }
      }
    );

    return id;
  } catch (err) {
    console.error("Error updating holiday:", err);
    throw new Error(err.message || "Failed to update holiday");
  }
};

const updateleave = async (leaveUpdateInput, { auth }) => {
  try {
    const userId = auth?.userId;
    if (!userId) throw new Error('Unauthorized user');

    const { id, ...updateData } = leaveUpdateInput;
    if (!id) throw new Error('Leave ID is required for update');

    const data = {
      ...updateData,
      updated_at: new Date(),
    };

    const [affectedRows] = await models.leave.update(data, {
      where: { id }
    });

    if (affectedRows === 0) {
      throw new Error(`No leave found with id ${id} to update`);
    }

    // Return only the ID, matching GraphQL schema expecting Int
    return id;

  } catch (err) {
    console.error("Error updating leave:", err);
    throw new Error(err.message || "Failed to update leave");
  }
};

const updateLeaveEmployee = async (emp_leaveUpdateInput, { auth }) => {
  try {
    const userId = auth?.userId;
    if (!userId) throw new Error('Unauthorized user');

    const { id, ...updateData } = emp_leaveUpdateInput;
    if (!id) throw new Error('Leave ID is required for update');

    const data = {
      ...updateData,
      updated_at: new Date(),
    };

    const [affectedRows] = await models.leave.update(data, {
      where: { id }
    });

    if (affectedRows === 0) {
      throw new Error(`No leave found with id ${id} to update`);
    }

    // Return only the ID, matching GraphQL schema expecting Int
    return id;

  } catch (err) {
    console.error("Error updating leave:", err);
    throw new Error(err.message || "Failed to update leave");
  }
};

const updateLeaveEmployeeApp = async (empLeaveUpdate, { auth }) => {
  try {
    const userId = auth?.userId;
    if (!userId) {
      return {
        success: false,
        message: 'Unauthorized user',
      };
    }

    const { id, ...updateData } = empLeaveUpdate;
    if (!id) {
      return {
        success: false,
        message: 'Leave ID is required for update',
      };
    }

    const data = {
      ...updateData,
      updated_at: new Date(),
    };

    const [affectedRows] = await models.leave.update(data, {
      where: { id },
    });

    if (affectedRows === 0) {
      return {
        success: false,
        message: `No leave found with id ${id} to update`,
      };
    }

    // Success case
    return {
      success: true,
      message: 'Leave updated successfully',
    };

  } catch (err) {
    console.error("Error updating leave:", err);
    return {
      success: false,
      message: err.message || "Failed to update leave",
    };
  }
};

const updateClient = async (clientUpdateInput, { auth }) => {
  try {
    const userId = auth?.userId;
    if (!userId) throw new Error('Unauthorized user');

    const { id, ...updateData } = clientUpdateInput;
    if (!id) throw new Error('Client ID is required for update');

    const data = {
      ...updateData,
      updated_at: new Date(),
    };

    const [affectedRows] = await models.client.update(data, {
      where: { id },
    });

    if (affectedRows === 0) {
      throw new Error(`No client found with ID ${id} to update`);
    }

    return true;

  } catch (err) {
    console.error("Error updating client:", err);
    throw new Error(err.message || "Failed to update client");
  }
};

const updateProfile = async (profileInput, { auth }) => {
  try {
    // 2. Extract employee_id and update fields
    const { employee_id, ...updateData } = profileInput;

    console.log('update Profile employee id', employee_id);

    if (!employee_id) {
      throw new Error("Employee ID is required for update");
    }

    // 3. Add updated_at timestamp
    const data = {
      ...updateData,
      updated_at: new Date(),
    };

    // 4. Perform the update
    const [affectedRows] = await models.employee.update(data, {
      where: { id: employee_id },
    });

    // 5. Handle case when no rows are updated
    if (affectedRows === 0) {
      return {
        success: false,
        message: `No employee found with employee_id ${employee_id} to update`,
      };
    }

    // 6. Return success response
    return {
      success: true,
      message: "Profile updated successfully",
    };
  } catch (err) {
    console.error("Error updating employee profile:", err);
    return {
      success: false,
      message: err.message || "Failed to update profile",
    };
  }
};

const updatepackage = async (packageUpdateInput, { auth }) => {
  try {
    const userId = auth?.userId;
    if (!userId) throw new Error('Unauthorized user');

    const { id } = packageUpdateInput;
    if (!id) throw new Error('Package ID is required for update');

    const data = {
      name: packageUpdateInput.name,
      plan_type: packageUpdateInput.plan_type || null,
      max_employees: packageUpdateInput.maxEmployees || 0,
      max_storage_size: packageUpdateInput.maxStorageSize || 0,
      storage_unit: packageUpdateInput.storage_unit || 'mb',
      sort: packageUpdateInput.position?.toString() || '0',
      is_private: packageUpdateInput.isPrivate ? 1 : 0,
      is_recommended: packageUpdateInput.isRecommended ? 1 : 0,
      monthly_price: packageUpdateInput.hasMonthlyPlan ? packageUpdateInput.monthlyPrice || 0 : 0,
      annual_price: packageUpdateInput.hasAnnualPlan ? packageUpdateInput.annualPrice || 0 : 0,
      module_in_package: packageUpdateInput.modules ? JSON.stringify(packageUpdateInput.modules) : '[]',
      description: packageUpdateInput.description || '',
      unit_id: packageUpdateInput.unit_id || '',

      updated_by: userId,
      updated_at: new Date(),
    };

    if (packageUpdateInput.currency) {
      const currency = await models.global_currency.findOne({
        where: { currency_code: packageUpdateInput.currency }
      });
      data.currency_id = currency ? currency.id : null;
    }

    const [affectedRows] = await models.package.update(data, {
      where: { id }
    });

    if (affectedRows === 0) {
      throw new Error(`No package found with id ${id} to update`);
    }

    console.log(`Package ${id} updated`, data);
    return id;

  } catch (err) {
    console.error("Error updating package:", err);
    throw new Error(err.message || "Failed to update package");
  }
};

const updateVendor = async (vendorUpdateInput, { auth }) => {
  try {
    if (!models?.vendor) {
      throw new Error('Vendor model not found');
    }

    const userId = auth?.userId;
    if (!userId) throw new Error('Unauthorized user');

    const { id } = vendorUpdateInput;
    if (!id) throw new Error('Vendor ID is required for update');

    const data = {
      vendor_name: vendorUpdateInput.vendor_name,
      opening_balance: vendorUpdateInput.opening_balance || 0,
      as_of_date: vendorUpdateInput.as_of_date || null,
      date_of_birth: vendorUpdateInput.date_of_birth || null,
      company_name: vendorUpdateInput.company_name || null,
      name_prefix: vendorUpdateInput.name_prefix || null,
      first_name: vendorUpdateInput.first_name || null,
      middle_initial: vendorUpdateInput.middle_initial || null,
      last_name: vendorUpdateInput.last_name || null,
      job_title: vendorUpdateInput.job_title || null,
      phone: vendorUpdateInput.phone || null,
      work_phone: vendorUpdateInput.work_phone || null,
      mobile: vendorUpdateInput.mobile || null,
      fax: vendorUpdateInput.fax || null,
      email: vendorUpdateInput.email || null,
      cc_email: vendorUpdateInput.cc_email || null,
      website: vendorUpdateInput.website || null,
      other: vendorUpdateInput.other || null,
      billed_street: vendorUpdateInput.billed_street || null,
      billed_suite: vendorUpdateInput.billed_suite || null,
      billed_zip: vendorUpdateInput.billed_zip || null,
      billed_city: vendorUpdateInput.billed_city || null,
      billed_state: vendorUpdateInput.billed_state || null,
      shipped_street: vendorUpdateInput.shipped_street || null,
      shipped_suite: vendorUpdateInput.shipped_suite || null,
      shipped_zip: vendorUpdateInput.shipped_zip || null,
      shipped_city: vendorUpdateInput.shipped_city || null,
      shipped_state: vendorUpdateInput.shipped_state || null,
      vendor_type_id: vendorUpdateInput.vendor_type_id || null,
      unit_id: vendorUpdateInput.unit_id || null,
      status: vendorUpdateInput.status || 'active',
      updated_by: userId,
      updated_at: new Date(),
    };

    const [affectedRows] = await models.vendor.update(data, {
      where: { id }
    });

    if (affectedRows === 0) {
      throw new Error(`Vendor with ID ${id} not found or no changes applied`);
    }

    console.log(`Vendor ${id} updated`, data);

    // Return number of rows updated (to match your GraphQL schema Int)
    return affectedRows;
  } catch (err) {
    console.error("Error updating Vendor:", err);
    throw new Error(err.message || "Failed to update Vendor");
  }
};


const updateVendorType = async (vendorTypeUpdateInput, { auth }) => {
  try {
    if (!models?.vendor_type) {
      throw new Error('Vendor Type model not found');
    }

    const userId = auth?.userId;
    if (!userId) throw new Error('Unauthorized user');

    const { id, vendor_title, vendor_parent, status, unit_id } = vendorTypeUpdateInput;
    if (!id) throw new Error('Vendor Type ID is required for update');

    const data = {
      vendor_title,
      unit_id,
      vendor_parent: vendor_parent || null,
      status: status || 'active',
      updated_by: userId,
      updated_at: new Date(),
    };

    const [affectedRows] = await models.vendor_type.update(data, {
      where: { id }
    });

    if (affectedRows === 0) {
      throw new Error(`Vendor Type with ID ${id} not found or no changes applied`);
    }

    console.log(`Vendor Type ${id} updated`, data);
    return true;
  } catch (err) {
    console.error("Error updating Vendor Type:", err);
    throw new Error(err.message || "Failed to update Vendor Type");
  }
};

const UpdateSubTask = async (updatesubTaskInput, { auth }) => {
  try {
    const userId = auth?.userId;
    if (!userId) throw new Error('Unauthorized user');

    const {
      id,
      title,
      start_date,
      due_date,
      description,
      status,
      task_id,
      assigned_to,
      assigned_by,
      unit_id,
    } = updatesubTaskInput;

    if (!id) throw new Error('Subtask ID is required for update');

    const existingSubTask = await models.sub_tasks.findByPk(id);
    if (!existingSubTask) throw new Error('Subtask not found');

    const updatedData = {
      title,
      start_date,
      due_date,
      description,
      status: status || existingSubTask.status,
      task_id,
      assigned_to,
      assigned_by,
      unit_id,
      updated_by: userId,
      updated_at: new Date(),
    };

    await existingSubTask.update(updatedData);

    console.log('Subtask updated:', existingSubTask.toJSON ? existingSubTask.toJSON() : existingSubTask);

    return true;
  } catch (error) {
    console.error('Error updating subtask:', error.message);
    throw new Error(error.message);
  }
};

const UpdateSubTaskStatus = async (updatesubTaskStatusInput, { auth }) => {
  try {
    const userId = auth?.userId;
    if (!userId) throw new Error('Unauthorized user');

    const {
      id,
      status,
      task_id,
      unit_id,
    } = updatesubTaskStatusInput;

    if (!id) throw new Error('Subtask ID is required for update');

    const existingSubTask = await models.sub_tasks.findByPk(id);
    if (!existingSubTask) throw new Error('Subtask not found');

    const updatedData = {
      status,
      updated_by: userId,
      updated_at: new Date(),
    };

    await existingSubTask.update(updatedData);

    return true;
  } catch (error) {
    console.error('Error updating subtask:', error.message);
    throw new Error(error.message);
  }
};

const UpdateTaskStatus = async (updateTaskStatusInput, { auth }) => {
  try {
    const userId = auth?.userId;
    if (!userId) throw new Error('Unauthorized user');

    const {
      id,
      status,
    } = updateTaskStatusInput;

    if (!id) throw new Error('tasks ID is required for update');

    const existingSubTask = await models.tasks.findByPk(id);
    if (!existingSubTask) throw new Error('tasks not found');

    const updatedData = {
      status,
      updated_by: userId,
      updated_at: new Date(),
    };

    await existingSubTask.update(updatedData);

    return true;
  } catch (error) {
    console.error('Error updating tasks:', error.message);
    throw new Error(error.message);
  }
};

const updateLeaveStatus = async (updateLeaveStatusInput, { auth }) => {
  try {
    const userId = auth?.userId;
    if (!userId) throw new Error('Unauthorized user');

    const { id, status } = updateLeaveStatusInput;
    if (!id) throw new Error('leave ID is required for update');

    const existingLeaveStatus = await models.leave.findByPk(id);
    if (!existingLeaveStatus) throw new Error('leave not found');

    await existingLeaveStatus.update({
      status,
      updated_by: userId,
      updated_at: new Date(),
    });

    return true;
  } catch (error) {
    console.error('Error updating leave:', error.message);
    throw new Error(error.message);
  }
};



const signUpUserByMobile = async (input, { auth }) => {
  try {
    const { email, password } = input;

    // Basic validation
    if (!email || !password) {
      throw new Error('Email and password are required');
    }


    console.log('Received from Flutter app:');
    console.log('Email:', email);
    console.log('Password:', password);


    return {
      id: 1,
      email,
      password,
    };
  } catch (err) {
    console.error('Error in signUpUserByMobile:', err);
    throw new Error(err.message || 'Failed to register user');
  }
};

const RegisterWithMobileHandle = async (input, { auth }) => {
  try {
    console.log('📩 Received from Flutter app:', input);

    const invitation = await models.invitation.findOne({
      where: { email: input.email },
      order: [['created_at', 'DESC']], // latest record
    });

    if (!invitation) {
      return {
        success: false,
        message: 'No invitation found for this email',
        employee: null,
      };
    }

    // 2️⃣ Verify OTP
    if (invitation.otp_code !== input.otp) {
      return {
        success: false,
        message: 'Invalid OTP code',
        employee: null,
      };
    }

    // 3️⃣ Check if email already exists in temporary_employees
    const existingEmployee = await models.temporary_employee.findOne({
      where: { email: input.email },
    });

    if (existingEmployee) {
      return {
        success: false,
        message: 'This email is already registered. Please login instead.',
        employee: null,
      };
    }

    // 4️⃣ Save into temporary_employee with unit_id from invitation
    const newEmployee = await models.temporary_employee.create({
      email: input.email,
      user_pass: input.user_pass,
      password: input.password,
      unit_id: invitation.unit_id,
      device_id: input.device_id,
      device_model: input.device_model,
      device_operating_system: input.device_OS,
      status: 0,
    });

    const existingAttempt = await models.login_attempt.findOne({
      where: { email: input.email },
    });

    if (existingAttempt) {
      await existingAttempt.update({ count: 0 });
    } else {
      await models.login_attempt.create({ email: input.email, count: 0 });
    }

    return {
      success: true,
      message: 'Registration successful',
      employee: {
        id: newEmployee.id,
        email: newEmployee.email,
        unit_id: newEmployee.unit_id,
      },
    };

  } catch (err) {
    console.error('❌ Error in RegisterWithMobileHandle:', err);

    // Catch unique constraint error just in case
    if (err.name === 'SequelizeUniqueConstraintError') {
      return {
        success: false,
        message: 'This email is already registered. Please login instead.',
        employee: null,
      };
    }

    return {
      success: false,
      message: err.message || 'Failed to register user',
      employee: null,
    };
  }
};

const completeRegistrationHandle = async (input, { auth }) => {
  try {
    if (!input?.id) {
      console.error("❌ Employee ID is required");
      return { success: false };
    }

    console.log("📥 Received from Flutter Form:", input);

    let faceEmbedding = input.face_embedding;

    if (faceEmbedding) {
      if (typeof faceEmbedding === "string") {
        try {
          // If it's already a valid JSON array string
          const parsed = JSON.parse(faceEmbedding);
          if (Array.isArray(parsed)) {
            faceEmbedding = parsed; // ✅ store as array, not string
          } else {
            throw new Error("Not an array");
          }
        } catch {
          // If it's just a raw comma-separated list
          faceEmbedding = faceEmbedding
            .replace(/^\[|\]$/g, "") // remove brackets if present
            .split(",")
            .map(v => parseFloat(v.trim()))
            .filter(v => !isNaN(v)); // drop invalid numbers
        }
      } else if (Array.isArray(faceEmbedding)) {
        // If Flutter sends an actual array
        faceEmbedding = faceEmbedding; // ✅ already good
      } else {
        // Any other type → ignore
        faceEmbedding = null;
      }
    }

    const updateData = {
      ...input,
      face_embedding: faceEmbedding // ✅ real JSON array
    };

    const [updatedRows] = await models.temporary_employee.update(updateData, {
      where: { id: input.id }
    });

    if (updatedRows === 0) {
      console.warn("⚠️ No employee found with the given ID");
      return { success: false };
    }

    console.log(`✅ Employee ${input.id} updated successfully`);
    return { success: true };
  } catch (err) {
    console.error("❌ Error in completeRegistrationHandle:", err);
    return { success: false };
  }
};

// const loginWithFaceHandle = async (input) => {
//   try {
//     console.log("📥 Login Request:", input);
//     const { device_id } = input;

//     if (!device_id) {
//       return { success: false, message: "Missing device_id", user: null };
//     }

//     // Fetch user by device_id
//     const users = await models.user.findAll({
//       where: { device_id },
//       raw: true,
//     });
//     console.log('login With Face Handle', users);

//     if (!users) {
//       console.log(`❌ No user found with device_id ${device_id}`);
//       return { success: false, message: "Device not recognized", users: null };
//     }

//     // Fetch employee linked to user
//     const userEmployeeMap = await models.user_employee_map.findAll({
//       where: { user_id: user.id },
//       attributes: ["employee_id"],
//       raw: true,
//     });

//     if (!userEmployeeMap) {
//       return { success: false, message: "No employee linked to this user", users: null };
//     }

//     const employee = await models.employee.findAll({
//       where: { id: userEmployeeMap.employee_id },
//       attributes: ["id"],
//       raw: true,
//     });

//     if (!employee) {
//       return { success: false, message: "Employee not found", user: null };
//     }
//     console.log('login With Face user', user);

//     const safeUser = {
//       user_id: user.id,
//       employee_id: employee.id,
//       name: user.name || null,
//       email: user.email || null,
//       password: user.user_pass,
//       status: user.status || null,
//       face_embedding: user.face_embedding,
//     };
//     console.log('login With Face user end result', safeUser);

//     return { success: true, message: "Face login successful", user: safeUser };
//   } catch (err) {
//     console.error("❌ Error in loginWithFaceHandle:", err);
//     return { success: false, message: "Error during face login", user: null };
//   }
// };


const loginWithFaceHandle = async (input) => {
  try {
    console.log("📥 Login Request:", input);
    const { device_id } = input;

    if (!device_id) {
      return { success: false, message: "Missing device_id", users: [] };
    }

    const users = await models.user.findAll({
      where: { device_id },
      raw: true,
    });

    if (!users || users.length === 0) {
      console.log(`❌ No users found with device_id ${device_id}`);
      return { success: false, message: "Device not recognized", users: [] };
    }

    const results = [];

    for (const user of users) {
      const userEmployeeMap = await models.user_employee_map.findOne({
        where: { user_id: user.id },
        attributes: ["employee_id", "unit_id"],
        raw: true,
      });
      if (!userEmployeeMap) continue;

      const employee = await models.employee.findOne({
        where: { id: userEmployeeMap.employee_id },
        attributes: ["id"],
        raw: true,
      });
      if (!employee) continue;

      let loginAttempt = await models.login_attempt.findOne({ where: { email: user.email } });
      if (loginAttempt) {
        loginAttempt = await loginAttempt.update({ count: loginAttempt.count + 1 });
      } else {
        loginAttempt = await models.login_attempt.create({ email: user.email, count: 1 });
      }

      results.push({
        user_id: user.id,
        unit_id: userEmployeeMap.unit_id,
        employee_id: employee.id,
        name: user.name || null,
        email: user.email || null,
        password: user.user_pass,
        status: user.status || null,
        face_embedding: user.face_embedding,
        login_count: loginAttempt.count,
      });
    }

    return {
      success: true,
      message: "Face login successful",
      users: results,
    };

  } catch (err) {
    console.error("❌ Error in loginWithFaceHandle:", err);
    return { success: false, message: "Error during face login", users: [] };
  }
};

const loginWithEmailHandle = async (input, { auth }) => {
  try {
    const { email, password } = input;

    if (!email || !password) {
      return { success: false, message: "Email and password are required", user: null };
    }

    const user = await models.user.findOne({
      where: { email },
      raw: true,
    });

    if (!user) {
      return { success: false, message: "Email not registered", user: null };
    }

    const hashedPassword = crypto.createHash("sha256").update(password).digest("hex");
    if (hashedPassword !== user.password) {
      return { success: false, message: "Incorrect password", user: null };
    }

    const userEmployeeMap = await models.user_employee_map.findOne({
      where: { user_id: user.id },
      attributes: ["employee_id"],
      raw: true,
    });

    

    let employee = null;
    if (userEmployeeMap?.employee_id) {
      employee = await models.employee.findOne({
        where: { id: userEmployeeMap.employee_id },
      attributes: ["unit_id"],

        raw: true,
      });
    }

    const safeUser = {
      user_id: user.id,
      employee_id: userEmployeeMap?.employee_id || null,
      unit_id: employee?.unit_id || null,
      name: user.name,
      email: user.email,
      status: user.status,
      face_embedding: user.face_embedding,
    };

    const payload = {
      userId: user.id,
      email: user.email,
      employeeId: userEmployeeMap?.employee_id || null,
      type: 'access'
    };

    const refreshPayload = {
      userId: user.id,
      email: user.email,
      type: 'refresh'
    };

    const expiresIn = '3600s';
    const refreshExpiresIn = '7d';

    const signOptions = {
      issuer: 'authorization/resource/ar/server',
      subject: 'argroup',
      audience: 'login',
      algorithm: 'HS256',
    };

    const token = jwt.sign(payload, process.env.JWT_SECRET, { ...signOptions, expiresIn });
    const refreshToken = jwt.sign(refreshPayload, process.env.JWT_SECRET, { ...signOptions, expiresIn: refreshExpiresIn });

    console.log('login with email application ', safeUser);
    
    return {
      success: true,
      message: "Login successful",
      user: safeUser,
      token,
      refreshToken,
      expiresIn,
      refreshExpiresIn,
    }; 

  } catch (err) {
    console.error("Error in login With Email Handle:", err);
    return {
      success: false,
      message: "An error occurred during email login",
      user: null,
    };
  }
};
// ✅ ADD TOKEN REFRESH ENDPOINT
const refreshTokenHandle = async (input) => {
  try {
    const { refreshToken } = input;

    if (!refreshToken) {
      return { success: false, message: "Refresh token required" };
    }

    const decoded = jwt.verify(refreshToken, process.env.JWT_SECRET, {
      issuer: 'authorization/resource/ar/server',
      subject: 'argroup',
      audience: 'login',
      algorithms: ['HS256'],
    });

    if (decoded.type !== 'refresh') {
      return { success: false, message: "Invalid token type" };
    }

    // Generate new access token
    const newPayload = {
      userId: decoded.userId,
      email: decoded.email,
      employeeId: decoded.employeeId,
      type: 'access'
    };

    const expiresIn = '3600s';
    const token = jwt.sign(newPayload, process.env.JWT_SECRET, {
      issuer: 'authorization/resource/ar/server',
      subject: 'argroup',
      audience: 'login',
      expiresIn,
      algorithm: 'HS256',
    });

    return {
      success: true,
      token,
      expiresIn,
    };

  } catch (err) {
    console.error("Token refresh error:", err);
    return {
      success: false,
      message: "Token refresh failed",
    };
  }
};


const verifyToken = (token) => {
  try {
    const decoded = jwt.verify(token, process.env.JWT_SECRET, {
      issuer: 'authorization/resource/ar/server',
      subject: 'argroup',
      audience: 'login',
      algorithms: ['HS256'],
    });
    return { valid: true, decoded };
  } catch (err) {
    console.error('Token verification failed:', err.message);
    return { valid: false, error: err.message };
  }
};

const logoutHandle = async (input, { auth }) => {
  try {
    console.log("📥 Logout Received from Flutter:", input);
    const { employee_id, user_id, logout_time, session_id, ip_address, user_agent } = input;

    if (!user_id || !logout_time) {
      return { success: false, message: "User ID and logout time are required" };
    }

    // 🔹 Insert record into user_logout table
    await models.user_logout.create({
      user_id,
      logout_time: new Date(logout_time),
      session_id: session_id || null,
      ip_address: ip_address || null,
      user_agent: user_agent || null,
      created_at: new Date()
    });

    console.log(`✅ Logout recorded for user ${user_id}`);

    return {
      success: true,
      message: "Logout successfully"
    };

  } catch (err) {
    console.error("❌ Error in logoutHandle:", err);
    return {
      success: false,
      message: "An error occurred during logout"
    };
  }
};

const checkInWithFaceHandle = async (input, { auth }) => {
  try {
    console.log("📥 Check-in Received:", input);
    const { employee_id, timestamp, location } = input;

    if (!employee_id || !timestamp || !location) {
      return { success: false, message: "Missing required fields" };
    }

    // 🔹 Validate employee exists
    const employee = await models.employee.findOne({
      where: { id: employee_id },
      attributes: ["id", "unit_id"],
      raw: true,
    });

    if (!employee) {
      return { success: false, message: "Employee not found" };
    }

    // 🔹 Get user_id from user_employee_map
    const userMap = await models.user_employee_map.findOne({
      where: { employee_id },
      attributes: ["user_id"],
      raw: true,
    });

    if (!userMap) {
      return { success: false, message: "No user linked to this employee" };
    }

    // 🔹 Fetch user embedding (just to check existence, no need to return it)
    const user = await models.user.findOne({
      where: { id: userMap.user_id },
      attributes: ["id", "face_embedding"],
      raw: true,
    });

    if (!user) {
      return { success: false, message: "Face data not registered for this employee" };
    }

    // 🔹 Get current date
    const today = new Date(timestamp).toISOString().split("T")[0];

    // 🔹 Check if already checked in
    const existingAttendance = await models.employee_attendance.findOne({
      where: { employee_id, date: today },
      raw: true,
    });

    if (existingAttendance) {
      return { success: false, message: "Already checked in today" };
    }

    // 🔹 Insert new attendance record
    await models.employee_attendance.create({
      unit_id: employee.unit_id,
      employee_id: employee.id,
      date: today,
      status: "present",
      clock_in_time: timestamp,
      working_from: "office",
      location,
      late: 0,
      half_day: 0,
      overwrite_attendance: 0,
      added_by: auth?.user?.id || 0,
      created_at: new Date(),
      updated_at: new Date(),
    });

    return { success: true, message: "Check-in successful" };

  } catch (err) {
    console.error("❌ Error in checkInHandle:", err);
    return { success: false, message: "An error occurred during check-in" };
  }
};

const checkOutWithFaceHandle = async (input, { auth }) => {
  try {
    console.log("📥 Check-out Received:", input);
    const { employee_id, timestamp, location } = input;

    if (!employee_id || !timestamp || !location) {
      return { success: false, message: "Missing required fields" };
    }

    // 🔹 Validate employee exists
    const employee = await models.employee.findOne({
      where: { id: employee_id },
      attributes: ["id", "unit_id"],
      raw: true,
    });

    if (!employee) {
      return { success: false, message: "Employee not found" };
    }

    // 🔹 Get user_id from mapping
    const userMap = await models.user_employee_map.findOne({
      where: { employee_id },
      attributes: ["user_id"],
      raw: true,
    });

    if (!userMap) {
      return { success: false, message: "No user linked to this employee" };
    }

    // 🔹 Fetch user embedding (only to check existence, not returned)
    const user = await models.user.findOne({
      where: { id: userMap.user_id },
      attributes: ["id", "face_embedding"],
      raw: true,
    });

    if (!user) {
      return { success: false, message: "Face data not registered for this employee" };
    }

    // 🔹 Get current date
    const today = new Date(timestamp).toISOString().split("T")[0];

    // 🔹 Find today’s attendance record
    const attendance = await models.employee_attendance.findOne({
      where: { employee_id, date: today },
    });

    if (!attendance) {
      return { success: false, message: "No check-in found for today" };
    }

    if (attendance.clock_out_time) {
      return {
        success: false,
        message: `Already checked out today at ${attendance.clock_out_time}`,
      };
    }

    // 🔹 Update record with check-out time
    await attendance.update({
      clock_out_time: timestamp,
      updated_at: new Date(),
    });

    return { success: true, message: "Check-out successful" };

  } catch (err) {
    console.error("❌ Error in checkOutHandle:", err);
    return { success: false, message: "An error occurred during check-out" };
  }
};

const checkInHandle = async (input, { auth }) => {
  // const userId = auth?.userId;
  // if (!userId) {
  //   console.error("Unauthorized user - no userId");
  //   return {
  //     success: false,
  //     message: "Unauthorized user - no userId",
  //   };
  // }

  // Get current date in Pakistan timezone (UTC+5)
  const now = new Date();
  const pakistanOffset = 5 * 60; // +5 hours in minutes
  const localTime = new Date(now.getTime() + pakistanOffset * 60 * 1000);

  // Format YYYY-MM-DD
  const today = localTime.toISOString().slice(0, 10);
  console.log("Today's date in Pakistan time:", today);

  const { employee_id, user_id, date, clock_in_time, location } = input;

  const formatDateTime = (day, time) => {
    if (!day || !time) return null;
    const dateTime = new Date(`${day}T${time}Z`); // Explicitly use UTC
    const pad = (n) => String(n).padStart(2, "0");
    return `${dateTime.getUTCFullYear()}-${pad(dateTime.getUTCMonth() + 1)}-${pad(dateTime.getUTCDate())} ${pad(dateTime.getUTCHours())}:${pad(dateTime.getUTCMinutes())}:${pad(dateTime.getUTCSeconds())}`;
  };

  try {
    // Check for existing shift roster
    const existingRoaster = await models.shift_roster.findOne({
      where: {
        employee_id: employee_id,
        date: today,
      },
    });

    console.log("Shift roster check:", existingRoaster);

    if (!existingRoaster) {
      console.warn(`⚠️ No shift roaster assigned for employee ${employee_id} on ${date}`);
      return {
        success: false,
        message: "No shift roaster assigned for this employee on this date.",
      };
    }

    const clockIn = formatDateTime(date, clock_in_time);

    // Create new attendance record
    const attendanceRecord = await models.employee_attendance.create({
      employee_id,
      date: today,
      clock_in_time: clockIn,
      location,
      added_by: user_id,
      status: 'Present',
      created_at: new Date(),
    });

    return {
      success: true,
      message: "Check-in recorded successfully.",
    };
  } catch (error) {
    console.error("❌ Error recording check-in:", error);
    return {
      success: false,
      message: `Error recording check-in: ${error.message}`,
    };
  }
};

const checkOutHandle = async (input, { auth }) => {
  const { employee_id, user_id, date, clock_out_time } = input;

  // Get current date in Pakistan timezone (UTC+5)
  const now = new Date();
  const pakistanOffset = 5 * 60; // +5 hours in minutes
  const localTime = new Date(now.getTime() + pakistanOffset * 60 * 1000);

  // Format YYYY-MM-DD
  const today = localTime.toISOString().slice(0, 10);
  console.log("Today's date in Pakistan time:", today);

  const formatDateTime = (day, time) => {
    if (!day || !time) return null;
    const dateTime = new Date(`${day}T${time}Z`); // Explicitly use UTC
    const pad = (n) => String(n).padStart(2, "0");
    return `${dateTime.getUTCFullYear()}-${pad(dateTime.getUTCMonth() + 1)}-${pad(dateTime.getUTCDate())} ${pad(dateTime.getUTCHours())}:${pad(dateTime.getUTCMinutes())}:${pad(dateTime.getUTCSeconds())}`;
  };

  try {
    // Check for existing shift roster
    const existingRoaster = await models.shift_roster.findOne({
      where: {
        employee_id: employee_id,
        date: today,
      },
    });

    console.log("Shift roster check:", existingRoaster);

    if (!existingRoaster) {
      console.warn(`⚠️ No shift roaster assigned for employee ${employee_id} on ${date}`);
      return {
        success: false,
        message: "No shift roaster assigned for this employee on this date.",
      };
    }

    // Find existing attendance record for the employee and date
    const attendanceRecord = await models.employee_attendance.findOne({
      where: {
        employee_id: employee_id,
        date: today,
      },
    });

    if (!attendanceRecord) {
      return {
        success: false,
        message: "No attendance record found for this employee on this date.",
      };
    }

    const clockOut = formatDateTime(date, clock_out_time);

    // Update existing attendance record
    await models.employee_attendance.update(
      {
        clock_out_time: clockOut,
        updated_at: new Date(),
      },
      {
        where: {
          employee_id: employee_id,
          date: today
        }
      }
    );

    return {
      success: true,
      message: "Check-out recorded successfully.",
    };
  } catch (error) {
    console.error("❌ Error recording check-out:", error);
    return {
      success: false,
      message: `Error recording check-out: ${error.message}`,
    };
  }
};

const saveExpensetype = async (expenseTypeInput, { auth }) => {
  try {
    const userId = auth?.userId;
    if (!userId) throw new Error('Unauthorized user');

    const data = {
      ...expenseTypeInput,
      created_by: userId,
      created_at: new Date(),
      updated_at: new Date(),
    };

    // Use the correct model name here
    const result = await models.ExpenseType.create(data);
    console.log('Expense Type created:', result.toJSON());

    return true;
  } catch (error) {
    console.error('Error in save Expense Type entry:', error.message);
    throw new Error(error.message);
  }
};

const swapTask = async (swapInput, { auth }) => {
  console.log("data comes form swapInput :", swapInput)
  try {

    if (!models?.task_approved) {
      return {
        success: false,
        message: "Task approved model not found",
      };
    }
    const { task_id, task_assign_id, from_employee_id, to_employee_id, created_by, reason, status, action } = swapInput;
    if (!task_id || !task_assign_id || !from_employee_id || !to_employee_id || !created_by || !status || !action) {
      return {
        success: false,
        message: "Missing required fields: task_id, task_assign_id, from_employee_id, to_employee_id, and status are required",
      };
    }
    // Optional: Validate if employees and task exist (assuming models.user and models.task exist)
    if (models.user) {

      const fromEmployee = await models.employee.findOne({ where: { id: from_employee_id } });
      const toEmployee = await models.employee.findOne({ where: { id: to_employee_id } });
      console.log(toEmployee, "toEmployee");
      console.log(fromEmployee, "fromEmployee");
      if (!fromEmployee || !toEmployee) {
        return {
          success: false,
          message: "One or both employees not found",
        };
      }
    }

    if (models.task) {
      const task = await models.tasks.findOne({ where: { id: task_id } });
      if (!task) {
        return {
          success: false,
          message: "Task not found",
        };
      }
    }
    console.log("action is :", action)
    // Prepare data for creation
    const data = {
      task_id,
      task_assign_id,
      from_employee_id,
      to_employee_id,
      reason,
      status,
      action,
      created_by,
      created_at: new Date(),
      updated_at: new Date(),
    };

    // Create the task swap record
    const result = await models.task_approved.create(data);
    console.log("Task swap created:", result.toJSON());

    return {
      success: true,
      message: "Task swap created successfully",
    };
  } catch (error) {
    console.error("Error in swap Task:", error.message);
    return {
      success: false,
      message: error.message,
    };
  }
};

const forwardTask = async (forwardInput, { auth }) => {
  console.log("data comes form forward Input :", forwardInput)
  try {

    if (!models?.task_approved) {
      return {
        success: false,
        message: "Task approved model not found",
      };
    }
    const { task_id, task_assign_id, from_employee_id, to_employee_id, created_by, reason, status, action } = swapInput;
    if (!task_id || !task_assign_id || !from_employee_id || !to_employee_id || !created_by || !status || !action) {
      return {
        success: false,
        message: "Missing required fields: task_id, task_assign_id, from_employee_id, to_employee_id, and status are required",
      };
    }
    // Optional: Validate if employees and task exist (assuming models.user and models.task exist)
    if (models.user) {

      const fromEmployee = await models.employee.findOne({ where: { id: from_employee_id } });
      const toEmployee = await models.employee.findOne({ where: { id: to_employee_id } });
      console.log(toEmployee, "toEmployee");
      console.log(fromEmployee, "fromEmployee");
      if (!fromEmployee || !toEmployee) {
        return {
          success: false,
          message: "One or both employees not found",
        };
      }
    }

    if (models.task) {
      const task = await models.tasks.findOne({ where: { id: task_id } });
      if (!task) {
        return {
          success: false,
          message: "Task not found",
        };
      }
    }
    console.log("action is :", action)
    // Prepare data for creation
    const data = {
      task_id,
      task_assign_id,
      from_employee_id,
      to_employee_id,
      reason,
      status,
      action,
      created_by,
      created_at: new Date(),
      updated_at: new Date(),
    };

    // Create the task swap record
    const result = await models.task_approved.create(data);
    console.log("Task forward  created:", result.toJSON());

    return {
      success: true,
      message: "Task forward  created successfully",
    };
  } catch (error) {
    console.error("Error in forward  Task:", error.message);
    return {
      success: false,
      message: error.message,
    };
  }
};

const AcceptConsent = async (acceptInput, { auth }) => {
  console.log("Data received from acceptInput:", acceptInput);

  try {
    // Create a new record in the signConsentDocs model
    const result = await models.signconsent_employee.create({
      sign_consent_id: acceptInput.sign_consent_id,
      employee_id: acceptInput.employee_id,
    });

    console.log("Consent document accepted and recorded:", result.toJSON());

    return {
      success: true,
      message: "Consent accepted successfully",
    };
  } catch (error) {
    console.error("Error while accepting consent:", error.message);
    return {
      success: false,
      message: error.message,
    };
  }
};

const AcceptConsentBulk = async (acceptInput, { auth }) => {
  console.log("Data received for bulk accept:", acceptInput);

  try {
    const { employee_id, sign_consent_ids } = acceptInput;

    // Prepare bulk data for multiple consent docs
    const bulkData = sign_consent_ids.map(signId => ({
      sign_consent_id: signId,
      employee_id: employee_id
    }));

    // Insert multiple records at once
    const result = await models.signconsent_employee.bulkCreate(bulkData);

    console.log("Bulk consent accepted:", result.map(r => r.toJSON()));

    return {
      success: true,
      message: `Employee accepted ${result.length} consent document(s) successfully`,
    };
  } catch (error) {
    console.error("Error while accepting bulk consent:", error.message);
    return {
      success: false,
      message: error.message,
    };
  }
};


const MarkApprovedTaskStatus = async (markApprovedTaskStatusInput, { auth }) => {
  console.log("data comes from task approve:", markApprovedTaskStatusInput);

  // try {
  //   if (!models?.task_approved || !models?.task_assign || !models?.tasks || !models?.employee) {
  //     console.error("Required models not found");
  //     return false;
  //   }

  //   const { id, status, message } = markApprovedTaskStatusInput;

  //   if (!id || !status) {
  //     console.error("Missing required fields");
  //     return false;
  //   }

  //   if (isNaN(status) || ![1, 2].includes(parseInt(status))) {
  //     console.error("Invalid status: must be 1 (approved) or 2 (rejected)");
  //     return false;
  //   }

  //   const taskApproved = await models.task_approved.findOne({ where: { id } });

  //   const {
  //     task_id,
  //     from_employee_id,
  //     to_employee_id,
  //     created_by,
  //     reason,
  //     action,
  //   } = taskApproved;

  //   const finalReason = message || reason;


  //   const taskAssign = await models.task_assign.findOne({ where: { id: task_id } });

  //   return await models.sequelize.transaction(async (t) => {
  //     await taskApproved.update(
  //       {
  //         status: parseInt(status),
  //         reason: finalReason,
  //         updated_at: new Date(),
  //       },
  //       { transaction: t }
  //     );

  //     console.log("Updated task_approved record:", taskApproved.toJSON());

  //     if (parseInt(status) === 1) {

  //       if (action === "swap") {

  //         const taskAssigns = await models.task_assign.findAll({
  //           where: { task_id: 30 },
  //           transaction: t
  //         });

  //         console.log('swap taskAssigns', taskAssigns);


  //         const updateFrom = await models.task_assign.update(
  //           { employee_id: to_employee_id },
  //           { where: { task_id, employee_id: from_employee_id }, transaction: t }
  //         );

  //         const updateTo = await models.task_assign.update(
  //           { employee_id: from_employee_id },
  //           { where: { task_id, employee_id: to_employee_id }, transaction: t }
  //         );

  //         console.log('Update results:', { updateFrom, updateTo });
  //       } else if (action === "forward") {

  //         console.log('🔁 Forward task started...', { task_id, to_employee_id });

  //         const taskAssignRecord = await models.task_assign.findOne({
  //           where: { id: task_id },
  //           transaction: t
  //         });

  //         if (!taskAssignRecord) {
  //           throw new Error(`❌ No task_assign record found for id ${task_id}`);
  //         }

  //         await taskAssignRecord.update(
  //           {
  //             employee_id: to_employee_id,
  //             updated_at: new Date()
  //           },
  //           { transaction: t }
  //         );

  //         console.log(`✅ Forwarded existing task id ${task_id} to employee ${to_employee_id}`);
  //       }

  //     } else {
  //       console.log(`Task ${task_id} rejected, no changes made to task_assign`);
  //     }

  //     return true;
  //   });
  // } catch (error) {
  //   console.error("Error in Mark Approved Task Status:", error.message);
  //   return false;
  // }
};

const MarkRejectTaskStatus = async (markRejectTaskStatusInput, { auth }) => {
  console.log("data comes from task reject:", markRejectTaskStatusInput);
  try {
    if (!models?.task_approved) {
      return {
        success: false,
        message: "Task approved model not found",
      };
    }

    const { id, status, message } = markRejectTaskStatusInput;

    const task = await models.task_approved.findOne({ where: { id } });
    if (!task) {
      return {
        success: false,
        message: "Task not found",
      };
    }

    await models.task_approved.update(
      {
        status,
        reason: message || null,
        updated_at: new Date(),
      },
      {
        where: { id },
      }
    );

    console.log(`✅ Task ${id} marked as rejected with message: ${message}`);

    return {
      success: true,
      message: "Task marked as rejected successfully",
    };
  } catch (error) {
    console.error("❌ Error in reject Task:", error.message);
    return {
      success: false,
      message: error.message,
    };
  }
};

const saveIncomeType = async (incomeTypeInput, { auth }) => {
  try {
    const userId = auth?.userId;
    if (!userId) throw new Error('Unauthorized user');

    const data = {
      ...incomeTypeInput,
      created_by: userId,
      created_at: new Date(),
      updated_at: new Date(),
    };

    const result = await models.income_type.create(data);
    console.log('income Type created:', result.toJSON());

    return true;
  } catch (error) {
    console.error('Error in saveincome Type entry:', error.message);
    throw new Error(error.message);
  }
};

const saveExpense = async (expensesInput, { auth }) => {
  try {
    const userId = auth?.userId;
    if (!userId) throw new Error('Unauthorized user');

    const data = {
      ...expensesInput,
      created_by: userId,
      created_at: new Date(),
      updated_at: new Date(),
    };

    const result = await models.expenses.create(data);
    console.log('Expense created:', result.toJSON());

    return true;
  } catch (error) {
    console.error('Error in save Expense entry:', error.message);
    throw new Error(error.message);
  }
};

const resolvers = {
  Date: GraphQLToolsTypes.Date({ name: 'Date' }),

  ArchiveFile: {
    user: archiveFile => {
      if (archiveFile.hasOwnProperty('user')) {
        return archiveFile.user
      }
      return models.user.findByPk(archiveFile.user_id)
    }
  },

  Employee: {
    unit: (employee) => {
      if (employee.hasOwnProperty('unit')) {
        return employee.unit
      }
      return models.unit.findByPk(employee.unit_id)
    },
    log: (employee) => {
      if (employee.hasOwnProperty('log')) {
        return employee.log
      }
      return models.employee_log.findAll({ where: { employee_id: employee.id }, order: [['created_at', 'DESC']] })
    },
    payroll_history: (employee) => {
      if (employee.hasOwnProperty('payroll_history')) {
        return employee.payroll_history
      }
      return models.employee_payroll.findAll({ where: { employee_id: employee.id }, order: [['created_at', 'DESC']] })
    }
  },
  EmployeePayrollHistory: {
    payroll: (employeePayrollHistory) => {
      if (employeePayrollHistory.hasOwnProperty('payroll')) {
        return employeePayrollHistory.payroll
      }
      return models.payroll.findByPk(employeePayrollHistory.payroll_id)
    }
  },
  EmployeeChange: {
    unit: (employeeChange) => {
      if (employeeChange.hasOwnProperty('unit')) {
        return employeeChange.unit
      }
      return models.unit.findByPk(employeeChange.unit_id)
    },
    employee: (employeeChange) => {
      if (employeeChange.hasOwnProperty('employee')) {
        return employeeChange.employee
      }
      return models.employee.findByPk(employeeChange.employee_id)
    }
  },

  EmployeePayroll: {
    employee: (employee_payroll) => {
      if (employee_payroll.hasOwnProperty('employee')) {
        return employee_payroll.employee
      }
      return models.employee.findByPk(employee_payroll.employee_id)
    },
    unit: (employee_payroll) => {
      if (employee_payroll.hasOwnProperty('unit')) {
        return employee_payroll.unit
      }
      return models.unit.findByPk(employee_payroll.unit_id)
    }
  },

  PayrollSummary: {
    unit: (payrollSummary) => {
      if (payrollSummary.hasOwnProperty('unit')) {
        return payrollSummary.unit
      }
      return models.unit.findByPk(payrollSummary.unit_id)
    }
  },

  Sale: {
    unit: (sale) => {
      if (sale.hasOwnProperty('unit')) {
        return sale.unit
      }
      return models.unit.findByPk(sale.unit_id)
    },
    expenses: (sale) => {
      if (sale.hasOwnProperty('sale_expenses')) {
        return sale.sale_expenses
      }
      return models.sales_expense.findAll({ where: { sale_id: sale.id } })
    },
    deposits: (sale) => {
      if (sale.hasOwnProperty('deposits')) {
        return sale.deposits
      }
      return models.sales_deposit.findAll({ where: { sale_id: sale.id } })
    },
    deliveries: (sale) => {
      if (sale.hasOwnProperty('deliveries')) {
        return sale.deliveries
      }
      return models.sales_food_delivery.findAll({ where: { sale_id: sale.id } })
    },
    logs: (sale) => {
      if (sale.hasOwnProperty('logs')) {
        return sale.logs
      }
      return models.sales_log.findAll({ where: { sale_id: sale.id } })
    }
  },

  Unit: {
    sales: (unit) => {
      if (unit.hasOwnProperty('sales')) {
        return unit.sales
      }
      return models.sale.findAll({ where: { unit_id: unit.id } })
    },
    banks: async (unit) => {
      if (unit.hasOwnProperty('banks')) {
        return unit.banks
      }
      const unitBanks = await models.unit_bank.findAll({
        where: {
          unit_id: unit.id
        }
      })
      return models.bank.findAll({
        where: {
          id: unitBanks.map(u => u.bank_id)
        },
        order: [
          ['name', 'ASC']
        ]
      })
    },
    franchise: async (unit) => {
      if (unit.hasOwnProperty('franchise')) {
        return unit.franchise
      }
      const unitFranchise = await models.unit_franchise.findOne({
        where: {
          unit_id: unit.id
        }
      })
      if (!unitFranchise) {
        return null
      }
      return models.franchise.findOne({
        where: {
          id: unitFranchise.franchise_id
        }
      })
    }
  },

  User: {
    access_flags: async (user) => {
      if (user.hasOwnProperty('access_flags')) {
        return user.access_flags
      }
      const user_access_flag = await models.user_access_flag.findOne({
        where: {
          user_id: user.id
        }
      })
      if (user_access_flag) {
        return user_access_flag.access_flags
      }
      return 255
    },
    user_group_id: (user) => {
      if (user.user_group_id <= 2) {
        return 2
      }
      if (user.user_group_id === 3) {
        return 3
      }
      return 4
    },
    user_group: (user) => {
      if (user.hasOwnProperty('user_group')) {
        return user.user_group
      }
      if (user.user_group_id <= 2) {
        return { id: 2, name: 'Admin' }
      }
      if (user.user_group_id === 3) {
        return { id: 3, name: 'OfficeManager' }
      }
      return { id: 4, name: 'UnitManager' }
      /*return models.user_group.findOne({
        where: {
          id: user.user_group_id
        }
      })*/
    },
    units: async (user) => {
      if (user.hasOwnProperty('units')) {
        return user.units
      }
      const userUnits = await models.unit_user.findAll({
        where: {
          user_id: user.id
        }
      })
      return models.unit.findAll({
        where: {
          id: userUnits.map(u => u.unit_id)
        }
      })
    }
  },

  Franchise: {
    suppliers: async (franchise) => {
      if (franchise.hasOwnProperty('suppliers')) {
        return franchise.suppliers
      }
      const franchiseSuppliers = await models.franchise_supplier.findAll({
        where: {
          franchise_id: franchise.id
        }
      })
      return models.supplier.findAll({
        where: {
          id: franchiseSuppliers.map(u => u.supplier_id),
        },
        order: [
          ['name', 'ASC']
        ]
      })
    }
  },

  UnitSummary: {
    unit: async (unitSummary) => {
      if (unitSummary.hasOwnProperty('unit')) {
        return unitSummary.unit
      }
      const unit = await models.unit.findOne({
        where: {
          id: unitSummary.unit_id
        }
      })
      if (unit) {
        return unit
      }
      return models.unit_old.findOne({
        where: {
          id: unitSummary.unit_id
        }
      })
    }
  },

  Query: {


    // fetch the profile of currenly athenticated user
    async me(_, args, { user }) {
      // Make sure user is logged in
      if (!user) {
        throw new Error('You are not authenticated!')
      }

      // user is authenticated
      return await User.findByPk(user.id)
    },

    isLogin: (_, args, { req }) => {
      //console.log(req.session)
      //console.log(req.session.user)
      return typeof req.session.user !== 'undefined'
    },

    bank: (_, { bank_id }) => models.bank.findByPk(bank_id),
    // banks: (_) => {
    //   return models.bank.findAll({
    //     order: [
    //       ['name', 'ASC']
    //     ]
    //   })
    // },

    banks: (_, { unit_id }) => {
      return models.NewBank.findAll({
        where: { unit_id },
        order: [
          ['id', 'ASC']
        ]
      })
    },


    franchise: (_, { franchise_id }) => {
      return models.franchise.findByPk(franchise_id)
    },
    franchises: (_) => {
      return models.franchise.findAll({
        order: [
          ['name', 'ASC']
        ]
      })
    },
    weekly_dates: async (_, { year, unit_id }) => {
      const unit = await models.unit.findByPk(unit_id)
      return weeklyDates(year, unit.payroll_start_day)
    },

    total_cash_in_hand: async (_, { unit_id, date }) => {
      return previousTotalCashInHand(unit_id, date)
    },

    employee_payroll: (_, { employee_payroll_id }) => models.employee_payroll.findByPk(employee_payroll_id),
    employee_payrolls: (_, args) => {
      const offset = args.offset || 0
      const limit = args.first || 10
      delete args.offset
      delete args.first
      return models.employee_payroll.findAll({ where: args, offset, limit })
    },

    employee: (_, { employee_id }) => models.employee.findByPk(employee_id),

    employee_payroll_history: (_, { employee_id }) =>
      models.employee_payroll.findAll({ where: { employee_id: employee_id }, order: [['created_at', 'DESC']] }),

    employees_for_unit: (_, args) => {
      const unitId = args.unit_id || -1
      return models.employee.findAll({
        where: {
          unit_id: unitId
        },
        include: [
          {
            model: models.department,
            as: 'department',
            attributes: ['name']
          }
        ]
      })
    },

    employee_detail: async (_, { employee_id }) => {
      const data = await models.employee.findByPk(employee_id, {
        include: [
          {
            model: models.department,
            as: 'department',
            attributes: ['name']
          }
        ]
      });

      console.log("fetchg data", data);
      return data;
    },


    expense: (_, { expense_id }) => models.expense.findByPk(expense_id),
    expenses: (_) => {
      return models.expense.findAll({
        order: [
          ['title', 'ASC']
        ]
      })
    },

    job_titles: (_) => models.job_title.findAll({
      order: [
        ['title', 'ASC']
      ]
    }),

    payroll: (_, { payroll_id }) => models.payroll.findByPk(payroll_id),
    payrolls: (_, args) => {
      const offset = args.offset || 0
      const limit = args.first || 10
      return models.payroll.findAll({ where: args.filter, offset, limit })
    },

    user: (_, { user_id }) => models.user.findByPk(user_id),
    users: (_) => {
      return models.user.findAll({})
    },
    user_groups: (_) => {
      return [
        {
          id: 2,
          name: 'Admin'
        },
        {
          id: 3,
          name: 'OfficeManager'

        },
        {
          id: 4,
          name: 'UnitManager'
        },
        // {
        //   id: 5,
        //   name: 'UnitManager'
        // },
        // {
        //   id: 6,
        //   name: 'UnitManager'
        // },
        {
          id: 7,
          name: 'Employee'
        }
      ]
    },
    user_units: async (_, { user_id }) => {
      const userUnits = await models.unit_user.findAll({
        where: {
          user_id: user_id
        }
      })
      return models.unit.findAll({
        where: {
          id: userUnits.map(u => u.unit_id)
        }
      })
    },
    unit: (_, { unit_id }) => models.unit.findByPk(unit_id),
    units: (_, args) => {
      const offset = args.offset
      const limit = args.first
      delete args.offset
      delete args.first
      return models.unit.findAll({ where: args, offset, limit })
    },

    sale: async (_, { sale_id }) => {
      const sale = await models.sale.findByPk(sale_id)
      return Object.assign(sale, {
        previous_cash_in_hand: previousTotalCashInHand(sale.unit_id, sale.sales_date)
      })
    },
    sales: (_, args) => {
      const offset = args.offset || 0
      const limit = args.first || 10
      const filter = args.filter || {}
      delete args.offset
      delete args.first
      return models.sale.findAll({ where: filter, offset, limit })
    },
    sales_details: async (_, args) => {
      const month = args.month
      const year = args.year
      const unit_id = args.unit_id
      /*const sales = await models.sale.findAll({
        where: {
          [Op.and]: [
            sequelize.where(sequelize.fn('MONTH', sequelize.col('sales_date')), month),
            sequelize.where(sequelize.fn('YEAR', sequelize.col('sales_date')), year),
            { unit_id: unit_id }
          ]
        },
        order: [
          ['sales_date', 'ASC']
        ]
      })*/

      const days = new Date(year, month, 0).getDate()
      let previousMonth = month - 1
      let nextMonth = month + 1
      let previousYear = year
      let nextYear = year
      if (previousMonth < 1) {
        previousMonth = 12
        previousYear = year - 1
      }
      if (nextMonth > 12) {
        nextMonth = 1
        nextYear = year + 1
      }
      const previousDays = new Date(previousYear, previousMonth, 0).getDate()

      const startDate = moment([year, month - 1, 1, 0, 0, 0])
      const endDate = moment(startDate).endOf('month')

      const sales = await models.sale.findAll({
        attributes: {
          include: [
            [sequelize.fn('MONTH', sequelize.col('sales_date')), 'month'],
            [sequelize.fn('YEAR', sequelize.col('sales_date')), 'year']
          ]
        },
        raw: true,
        having: {
          [Op.and]: [
            { month: month },
            { year: year },
            { unit_id: unit_id }
          ]
        },
        order: [
          [sequelize.fn('DATE', models.sequelize.col('sales_date')), 'ASC']
        ]
      })

      /*const sales = await models.sale.findAll({
        where: {
          [Op.and]: [
            {
              date: {
                [Op.gte]: startDate.format('YYYY-MM-DD')
              }
            },
            {
              date: {
                [Op.lte]: endDate.format('YYYY-MM-DD')
              }
            },
            { unit_id: unit_id }
          ]
        },
        order: [
          ['date', 'ASC']
        ]
      })*/

      const cashInHand = await models.sale.findOne({
        attributes: [
          [sequelize.fn('SUM', sequelize.col('cash_in_hand')), 'total_cash_in_hand']
        ],
        where: {
          [Op.and]: [
            {
              sales_date: {
                [Op.lt]: startDate.format('YYYY-MM-DD')
              }
            },
            {
              unit_id: unit_id
            }
          ]
        }
      })
      var previous_cash_in_hand = cashInHand.dataValues.total_cash_in_hand || 0.00
      const saleIds = []
      const salesMap = new Map()
      sales.forEach(s => {
        const key = moment(s.sales_date).format('YYYY-MM-DD')
        // console.log(key, s.gross_sales, s.sales_date)
        salesMap.set(key, s)
        saleIds.push(s.id)
      })
      const totalExpenseMap = new Map()
      const totalExpenses = await models.sales_expense.findAll({
        attributes: [
          'sale_id',
          [sequelize.fn('sum', sequelize.col('amount')), 'amount'],
        ],
        where: {
          sale_id: saleIds
        },
        group: [
          'sale_id'
        ]
      })
      totalExpenses.forEach(e => {
        totalExpenseMap.set(e.sale_id, e.amount)
      })
      const totalDepositMap = new Map()
      const totalDeposits = await models.sales_deposit.findAll({
        attributes: [
          'sale_id',
          [sequelize.fn('sum', sequelize.col('amount')), 'amount'],
        ],
        where: {
          sale_id: saleIds
        },
        group: [
          'sale_id'
        ]
      })
      totalDeposits.forEach(d => {
        totalDepositMap.set(d.sale_id, d.amount)
      })
      let day = moment(startDate)
      while (day.month() === (month - 1)) {
        const key = moment(day).format('YYYY-MM-DD')
        if (!salesMap.has(key)) {
          const missingSale = Object.assign(
            models.sale.build({
              id: -(1000000 * (year - 2000) + 1000 * unit_id + day.date()),
              status: -1,
              sales_date: moment(day).format('YYYY-MM-DD'),
              createdAt: moment(day).format('YYYY-MM-DD 00:00:00'),
              updatedAt: moment(day).format('YYYY-MM-DD 00:00:00'),
            }),
            {
              sales_date: key,
              total_expenses: 0.0,
              total_deposits: 0.0,
              previous_cash_in_hand: previous_cash_in_hand,
            })
          salesMap.set(key, missingSale)
        }
        else {
          // console.log(day, moment(map.get(day).createdAt).utc(),
          // moment(`${year}-${month}-${day}`, 'YYYY-MM-DD').utc(), map.get(day).gross_sales)
          // map.get(key).previous_cash_in_hand = previous_cash_in_hand
          const sales = salesMap.get(key)
          salesMap.set(key, Object.assign(sales,
            {
              total_expenses: totalExpenseMap.has(sales.id) ? totalExpenseMap.get(sales.id) : 0.0,
              total_deposits: totalDepositMap.has(sales.id) ? totalDepositMap.get(sales.id) : 0.0,
              previous_cash_in_hand: previous_cash_in_hand
            }
          ))
          //map.get(key).date = map.get(key).sales_date
          //updatedAt: moment(day).format('YYYY-MM-DD 00:00:00'),
          previous_cash_in_hand += salesMap.get(key).cash_in_hand
        }
        day = day.add(1, 'days')
      }
      //console.log(sales)
      return [...salesMap.values()]
    },

    // SELECT sum(net_sales),WEEK(DATE_SUB(created_at, INTERVAL 30 DAY)) as week, YEAR(created_at) as year FROM `sales`
    // WHERE unit_id=3 GROUP BY week HAVING year=2018 
    sales_weekly: async (_, { year, unit_id }) => {
      const unit = await models.unit.findByPk(unit_id)
      const payrollStartDay = unit.payroll_start_day
      let referenceDate = moment('20161225', "YYYYMMDD").add(payrollStartDay, 'day')
      let from
      let to
      while (true) {
        if (!from && referenceDate.year() === year) {
          from = moment(referenceDate)
        }
        if (referenceDate.year() > year) {
          break
        }
        to = moment(referenceDate).subtract(1, 'day')
        referenceDate = referenceDate.add(1, 'week')
      }
      const salesAggregates = await models.sale.findAll({
        attributes: [
          [sequelize.fn('sum', sequelize.col('gross_sales')), 'gross_sales'],
          [sequelize.fn('sum', sequelize.col('tax')), 'tax'],
          [sequelize.fn('sum', sequelize.col('net_sales')), 'net_sales'],
          [sequelize.fn('sum', sequelize.col('net_sales_uber_eats')), 'net_sales_uber_eats'],
          [sequelize.fn('sum', sequelize.col('tax_uber_eats')), 'tax_uber_eats'],
          [sequelize.fn('sum', sequelize.col('net_sales_postmates')), 'net_sales_postmates'],
          [sequelize.fn('sum', sequelize.col('tax_postmates')), 'tax_postmates'],
          [sequelize.fn('sum', sequelize.col('credit_sales')), 'credit_sales'],
          [sequelize.fn('sum', sequelize.col('amex_credit_sales')), 'amex_credit_sales'],
          [sequelize.fn('sum', sequelize.col('master_credit_sales')), 'master_credit_sales'],
          [sequelize.fn('sum', sequelize.col('discover_credit_sales')), 'discover_credit_sales'],
          [sequelize.fn('sum', sequelize.col('visa_credit_sales')), 'visa_credit_sales'],
          [sequelize.fn('sum', sequelize.col('debit_sales')), 'debit_sales'],
          [sequelize.fn('sum', sequelize.col('gift_card_redeem')), 'gift_card_redeem'],
          [sequelize.fn('sum', sequelize.col('gift_card_sold')), 'gift_card_sold'],
          [sequelize.fn('sum', sequelize.col('donations')), 'donations'],
          [sequelize.fn('sum', sequelize.col('cash')), 'cash'],
          [sequelize.fn('sum', sequelize.col('rbi_mobile_app')), 'rbi_mobile_app'],
          [sequelize.fn('sum', sequelize.col('uber_eats')), 'uber_eats'],
          [sequelize.fn('sum', sequelize.col('grubhub')), 'grubhub'],
          [sequelize.fn('sum', sequelize.col('doordash')), 'doordash'],
          [sequelize.fn('sum', sequelize.col('white_label')), 'white_label'],
          [sequelize.fn('sum', sequelize.col('postmates')), 'postmates'],
          [sequelize.fn('sum', sequelize.col('snackpass')), 'snackpass'],
          [sequelize.fn('sum', sequelize.col('transactions')), 'transactions'],
          [sequelize.fn('sum', sequelize.col('voids')), 'voids'],
          [sequelize.fn('sum', sequelize.col('voids_amount')), 'voids_amount'],
          [sequelize.fn('sum', sequelize.col('refunds')), 'refunds'],
          [sequelize.fn('sum', sequelize.col('refunds_amount')), 'refunds_amount'],
          [sequelize.fn('sum', sequelize.col('discounts')), 'discounts'],
          [sequelize.fn('sum', sequelize.col('discounts_amount')), 'discounts_amount'],
          [sequelize.fn('YEAR', sequelize.col('sales_date')), 'year'],
          [sequelize.fn('WEEK', sequelize.fn('DATE_SUB', sequelize.col('sales_date'), sequelize.literal(`INTERVAL ${payrollStartDay} DAY`))), 'week']
        ],
        group: [
          'week',
        ],
        where: {
          [Op.and]: [
            {
              sales_date: {
                [Op.gte]: from.format('YYYY-MM-DD')
              }
            },
            {
              sales_date: {
                [Op.lte]: to.format('YYYY-MM-DD')
              }
            },
            {
              unit_id: unit_id
            }
          ]
        }
      })
      let salesWeekly = []
      salesAggregates.forEach((salesAggregate, i) => {
        salesWeekly.push({
          id: 1000000 * (year - 2000) + 1000 * unit_id + i,
          from: moment(from).add(i, 'weeks'),
          to: moment(from).add(6, 'days').add(i, 'weeks'),
          sale: {
            id: i,
            unit_id: unit_id,
            gross_sales: salesAggregate.gross_sales,
            tax: salesAggregate.tax,
            net_sales: salesAggregate.net_sales,
            net_sales_uber_eats: salesAggregate.net_sales_uber_eats,
            tax_uber_eats: salesAggregate.tax_uber_eats,
            net_sales_postmates: salesAggregate.net_sales_postmates,
            tax_postmates: salesAggregate.tax_postmates,
            credit_sales: salesAggregate.credit_sales,
            amex_credit_sales: salesAggregated.amex_credit_sales,
            master_credit_sales: salesAggregated.master_credit_sales,
            discover_credit_sales: salesAggregated.discover_credit_sales,
            visa_credit_sales: salesAggregated.visa_credit_sales,
            debit_sales: salesAggregated.debit_sales,
            gift_card_redeem: salesAggregated.gift_card_redeem,
            gift_card_sold: salesAggregated.gift_card_sold,
            donations: salesAggregated.donations,
            cash: salesAggregated.cash,
            rbi_mobile_app: salesAggregated.rbi_mobile_app,
            uber_eats: salesAggregated.uber_eats,
            grubhub: salesAggregated.grubhub,
            doordash: salesAggregated.doordash,
            white_label: salesAggregated.white_label,
            postmates: salesAggregated.postmates,
            snackpass: salesAggregated.snackpass,
            transactions: salesAggregate.transactions,
            voids: salesAggregate.voids,
            voids_amount: salesAggregate.voids_amount,
            refunds: salesAggregate.refunds,
            refunds_amount: salesAggregate.refunds_amount,
            discounts: salesAggregate.discounts,
            discounts_amount: salesAggregate.discounts_amount
          }
        })
      })
      return salesWeekly
    },

    sales_weekly2: async (_, { year, unit_id }) => {
      const unit = await models.unit.findByPk(unit_id)
      const unitPayrollPeriod = unit.payroll_period
      const unitPayrollStartDay = unit.payroll_start_day
      const payrolls = await models.payroll.findAll({
        where: {
          unit_id: unit_id
        },
        order: [
          ['created_at', 'ASC']
        ]
      })
      var referenceDate = moment('20161225', "YYYYMMDD").utc().add(unitPayrollStartDay, 'day')
      while (true) {
        if (referenceDate.year() == year) {
          break
        }
        referenceDate = referenceDate.add(unitPayrollPeriod, 'week')
      }
      const yearStart = moment(year + '0101', "YYYYMMDD")
      const previousYearPayrollEnd = referenceDate.add(-1, 'day')
      //yearStart.startOf('week') === yearStart
      //    ? yearStart.add(-1, 'week').add(-1, 'day') : yearStart.startOf('week').add(-1, 'day')
      const payrollWeeks = payrolls
        .map(p => {
          const tokens = p.period.split('>')
          return {
            id: p.id,
            unit_id: p.unit_id,
            status: p.status,
            createdAt: p.createdAt,
            updatedAt: p.updatedAt,
            range: [moment(tokens[0], "YYYY-MM-DD"), moment(tokens[1], "YYYY-MM-DD")],
          }
        })
        .filter(o => o.range[0].isAfter(previousYearPayrollEnd))
        .map(o => {
          return {
            range: o.range,
            period: createPeriod(o.range[0], o.range[1]),
            id: o.id,
            unit_id: o.unit_id,
            hours: 0.0,
            amount: 0.0,
            status: o.status,
            createdAt: o.createdAt,
            updatedAt: o.updatedAt,
          }
        })

      for (var i = 0; i < payrollWeeks.length; i++) {
        payrollWeeks[i].hours = await models.employee_payroll.sum('hours', {
          where: {
            payroll_id: payrollWeeks[i].id
          }
        })
        payrollWeeks[i].amount = await models.employee_payroll.sum('total_expense', {
          where: {
            payroll_id: payrollWeeks[i].id
          }
        })
      }

      var salesWeekly = []
      var endOfWeek = previousYearPayrollEnd
      var i = 0
      for (i = 0; i < payrollWeeks.length; i++) {
        const salesAggregated = await models.sale.findOne({
          attributes: [
            [sequelize.fn('sum', sequelize.col('gross_sales')), 'gross_sales'],
            [sequelize.fn('sum', sequelize.col('tax')), 'tax'],
            [sequelize.fn('sum', sequelize.col('net_sales')), 'net_sales'],
            [sequelize.fn('sum', sequelize.col('net_sales_uber_eats')), 'net_sales_uber_eats'],
            [sequelize.fn('sum', sequelize.col('tax_uber_eats')), 'tax_uber_eats'],
            [sequelize.fn('sum', sequelize.col('net_sales_postmates')), 'net_sales_postmates'],
            [sequelize.fn('sum', sequelize.col('tax_postmates')), 'tax_postmates'],
            [sequelize.fn('sum', sequelize.col('credit_sales')), 'credit_sales'],
            [sequelize.fn('sum', sequelize.col('amex_credit_sales')), 'amex_credit_sales'],
            [sequelize.fn('sum', sequelize.col('master_credit_sales')), 'master_credit_sales'],
            [sequelize.fn('sum', sequelize.col('discover_credit_sales')), 'discover_credit_sales'],
            [sequelize.fn('sum', sequelize.col('visa_credit_sales')), 'visa_credit_sales'],
            [sequelize.fn('sum', sequelize.col('debit_sales')), 'debit_sales'],
            [sequelize.fn('sum', sequelize.col('gift_card_redeem')), 'gift_card_redeem'],
            [sequelize.fn('sum', sequelize.col('gift_card_sold')), 'gift_card_sold'],
            [sequelize.fn('sum', sequelize.col('donations')), 'donations'],
            [sequelize.fn('sum', sequelize.col('cash')), 'cash'],
            [sequelize.fn('sum', sequelize.col('rbi_mobile_app')), 'rbi_mobile_app'],
            [sequelize.fn('sum', sequelize.col('uber_eats')), 'uber_eats'],
            [sequelize.fn('sum', sequelize.col('grubhub')), 'grubhub'],
            [sequelize.fn('sum', sequelize.col('doordash')), 'doordash'],
            [sequelize.fn('sum', sequelize.col('white_label')), 'white_label'],
            [sequelize.fn('sum', sequelize.col('postmates')), 'postmates'],
            [sequelize.fn('sum', sequelize.col('snackpass')), 'snackpass'],
            [sequelize.fn('sum', sequelize.col('transactions')), 'transactions'],
            [sequelize.fn('sum', sequelize.col('voids')), 'voids'],
            [sequelize.fn('sum', sequelize.col('voids_amount')), 'voids_amount'],
            [sequelize.fn('sum', sequelize.col('refunds')), 'refunds'],
            [sequelize.fn('sum', sequelize.col('refunds_amount')), 'refunds_amount'],
            [sequelize.fn('sum', sequelize.col('discounts')), 'discounts'],
            [sequelize.fn('sum', sequelize.col('discounts_amount')), 'discounts_amount']
          ],
          where: {
            [Op.and]: [
              {
                sales_date: {
                  [Op.gte]: payrollWeeks[i].range[0]
                }
              },
              {
                sales_date: {
                  [Op.lte]: payrollWeeks[i].range[1]
                }
              },
              {
                unit_id: unit_id
              }
            ]
          }
        })
        salesWeekly.push({
          id: 1000000 * (year - 2000) + 1000 * unit_id + i,
          from: payrollWeeks[i].range[0],
          to: payrollWeeks[i].range[1],
          sale: {
            id: i,
            gross_sales: salesAggregated.gross_sales,
            tax: salesAggregated.tax,
            net_sales: salesAggregated.net_sales,
            net_sales_uber_eats: salesAggregated.net_sales_uber_eats,
            tax_uber_eats: salesAggregated.tax_uber_eats,
            net_sales_postmates: salesAggregated.net_sales_postmates,
            tax_postmates: salesAggregated.tax_postmates,
            credit_sales: salesAggregated.credit_sales,
            amex_credit_sales: salesAggregated.amex_credit_sales,
            master_credit_sales: salesAggregated.master_credit_sales,
            discover_credit_sales: salesAggregated.discover_credit_sales,
            visa_credit_sales: salesAggregated.visa_credit_sales,
            debit_sales: salesAggregated.debit_sales,
            gift_card_redeem: salesAggregated.gift_card_redeem,
            gift_card_sold: salesAggregated.gift_card_sold,
            donations: salesAggregated.donations,
            cash: salesAggregated.cash,
            rbi_mobile_app: salesAggregated.rbi_mobile_app,
            uber_eats: salesAggregated.uber_eats,
            grubhub: salesAggregated.grubhub,
            doordash: salesAggregated.doordash,
            white_label: salesAggregated.white_label,
            postmates: salesAggregated.postmates,
            snackpass: salesAggregated.snackpass,
            transactions: salesAggregated.transactions,
            voids: salesAggregated.voids,
            voids_amount: salesAggregated.voids_amount,
            refunds: salesAggregated.refunds,
            refunds_amount: salesAggregated.refunds_amount,
            discounts: salesAggregated.discounts,
            discounts_amount: salesAggregated.discounts_amount
          }
        })
        endOfWeek = payrollWeeks[i].range[1]
        if (endOfWeek.year() > year) {
          break
        }
      }
      return salesWeekly
    },

    sales_weekly3: async (_, { year, unit_id }) => {
      const unit = await models.unit.findByPk(unit_id)
      const payrollStartDay = unit.payroll_start_day
      let referenceDate = moment('20151227', "YYYYMMDD").add(payrollStartDay, 'day')
      let from
      let to
      let weekCount = 0
      while (true) {
        if (!from && referenceDate.year() === year) {
          from = moment(referenceDate)
          if (referenceDate.dayOfYear() > 2) {
            from = moment(referenceDate).subtract(1, 'week')
          }
        }
        if (from) {
          weekCount++
        }
        if (weekCount > 53) {
          to = moment(referenceDate).subtract(1, 'day')
          break
        }
        referenceDate = referenceDate.add(1, 'week')
      }
      const salesYear = await models.sale.findAll({
        where: {
          [Op.and]: [
            sequelize.where(sequelize.fn('YEAR', sequelize.col('sales_date')), year),
            { unit_id: unit_id }
          ]
        }
      })

      let count = 0
      let gross_sales = 0.0
      let tax = 0.0
      let net_sales = 0.0
      let net_sales_uber_eats = 0.0
      let tax_uber_eats = 0.0
      let net_sales_postmates = 0.0
      let tax_postmates = 0.0
      let credit_sales = 0.0
      let amex_credit_sales = 0.0
      let master_credit_sales = 0.0
      let discover_credit_sales = 0.0
      let visa_credit_sales = 0.0
      let debit_sales = 0.0
      let gift_card_redeem = 0.0
      let gift_card_sold = 0.0
      let donations = 0.0
      let cash = 0.0
      let rbi_mobile_app = 0.0
      let uber_eats = 0.0
      let grubhub = 0.0
      let doordash = 0.0
      let white_label = 0.0
      let postmates = 0.0
      let snackpass = 0.0
      let transactions = 0
      let voids = 0
      let voids_amount = 0.0
      let refunds = 0
      let refunds_amount = 0.0
      let discounts = 0
      let discounts_amount = 0.0
      let salesWeekly = []

      const dayCount = to.diff(from, 'days') + 1
      const saleByDayIndex = new Array(dayCount).fill(null)
      salesYear.forEach(sales => {
        const days = - from.diff(sales.sales_date, 'days')
        saleByDayIndex[days] = sales
      })
      saleByDayIndex.forEach((sales, i) => {
        if (sales) {
          count++
          gross_sales += sales.gross_sales
          tax += sales.tax
          net_sales += sales.net_sales
          net_sales_uber_eats += sales.net_sales_uber_eats
          tax_uber_eats += sales.tax_uber_eats
          net_sales_postmates += sales.net_sales_postmates
          tax_postmates += sales.tax_postmates
          credit_sales += sales.credit_sales
          amex_credit_sales += sales.amex_credit_sales
          master_credit_sales += sales.master_credit_sales
          discover_credit_sales += sales.discover_credit_sales
          visa_credit_sales += sales.visa_credit_sales
          debit_sales += sales.debit_sales
          gift_card_redeem += sales.gift_card_redeem
          gift_card_sold += sales.gift_card_sold
          donations += sales.donations
          cash += sales.cash
          rbi_mobile_app += sales.rbi_mobile_app
          uber_eats += sales.uber_eats
          grubhub += sales.grubhub
          doordash += sales.doordash
          white_label += sales.white_label
          postmates += sales.postmates
          snackpass += sales.snackpass
          transactions += sales.transactions
          voids += sales.voids
          voids_amount += sales.voids_amount
          refunds += sales.refunds
          refunds_amount += sales.refunds_amount
          discounts += sales.discounts
          discounts_amount += sales.discounts_amount
        }

        if (((i + 1) % 7) === 0) {
          salesWeekly.push({
            id: 1000000 * (year - 2000) + 1000 * unit_id + i,
            from: moment(from).add(i - 6, 'days'),
            to: moment(from).add(i, 'days'),
            missing_count: 7 - count,
            day_count: count,
            sale: count === 0 ? {} : {
              id: i,
              unit_id: unit_id,
              gross_sales: gross_sales,
              tax: tax,
              net_sales: net_sales,
              net_sales_uber_eats: net_sales_uber_eats,
              tax_uber_eats: tax_uber_eats,
              net_sales_postmates: net_sales_postmates,
              tax_postmates: tax_postmates,
              credit_sales: credit_sales,
              amex_credit_sales: amex_credit_sales,
              master_credit_sales: master_credit_sales,
              discover_credit_sales: discover_credit_sales,
              visa_credit_sales: visa_credit_sales,
              debit_sales: debit_sales,
              gift_card_redeem: gift_card_redeem,
              gift_card_sold: gift_card_sold,
              donations: donations,
              cash: cash,
              rbi_mobile_app: rbi_mobile_app,
              uber_eats: uber_eats,
              grubhub: grubhub,
              doordash: doordash,
              white_label: white_label,
              postmates: postmates,
              snackpass: snackpass,
              transactions: transactions,
              voids: voids,
              voids_amount: voids_amount,
              refunds: refunds,
              refunds_amount: refunds_amount,
              discounts: discounts,
              discounts_amount: discounts_amount
            }
          })
          count = 0
          gross_sales = 0
          tax = 0
          net_sales = 0
          net_sales_uber_eats = 0
          tax_uber_eats = 0
          net_sales_postmates = 0
          tax_postmates = 0
          credit_sales = 0
          amex_credit_sales = 0
          master_credit_sales = 0
          discover_credit_sales = 0
          visa_credit_sales = 0
          debit_sales = 0
          gift_card_redeem = 0
          gift_card_sold = 0
          donations = 0
          cash = 0
          rbi_mobile_app = 0
          uber_eats = 0
          grubhub = 0
          doordash = 0
          white_label = 0
          postmates = 0
          snackpass = 0
          transactions = 0
          voids = 0
          voids_amount = 0
          refunds = 0
          refunds_amount = 0
          discounts = 0
          discounts_amount = 0
        }
      })
      return salesWeekly
    },

    sales_monthly: async (_, { year, unit_id }) => {
      const salesAggregated = await models.sale.findAll({
        attributes: [
          [sequelize.fn('sum', sequelize.col('gross_sales')), 'gross_sales'],
          [sequelize.fn('sum', sequelize.col('tax')), 'tax'],
          [sequelize.fn('sum', sequelize.col('net_sales')), 'net_sales'],
          [sequelize.fn('sum', sequelize.col('net_sales_uber_eats')), 'net_sales_uber_eats'],
          [sequelize.fn('sum', sequelize.col('tax_uber_eats')), 'tax_uber_eats'],
          [sequelize.fn('sum', sequelize.col('net_sales_postmates')), 'net_sales_postmates'],
          [sequelize.fn('sum', sequelize.col('tax_postmates')), 'tax_postmates'],
          [sequelize.fn('sum', sequelize.col('credit_sales')), 'credit_sales'],
          [sequelize.fn('sum', sequelize.col('amex_credit_sales')), 'amex_credit_sales'],
          [sequelize.fn('sum', sequelize.col('master_credit_sales')), 'master_credit_sales'],
          [sequelize.fn('sum', sequelize.col('discover_credit_sales')), 'discover_credit_sales'],
          [sequelize.fn('sum', sequelize.col('visa_credit_sales')), 'visa_credit_sales'],
          [sequelize.fn('sum', sequelize.col('debit_sales')), 'debit_sales'],
          [sequelize.fn('sum', sequelize.col('gift_card_redeem')), 'gift_card_redeem'],
          [sequelize.fn('sum', sequelize.col('gift_card_sold')), 'gift_card_sold'],
          [sequelize.fn('sum', sequelize.col('donations')), 'donations'],
          [sequelize.fn('sum', sequelize.col('cash')), 'cash'],
          [sequelize.fn('sum', sequelize.col('rbi_mobile_app')), 'rbi_mobile_app'],
          [sequelize.fn('sum', sequelize.col('uber_eats')), 'uber_eats'],
          [sequelize.fn('sum', sequelize.col('grubhub')), 'grubhub'],
          [sequelize.fn('sum', sequelize.col('doordash')), 'doordash'],
          [sequelize.fn('sum', sequelize.col('white_label')), 'white_label'],
          [sequelize.fn('sum', sequelize.col('postmates')), 'postmates'],
          [sequelize.fn('sum', sequelize.col('snackpass')), 'snackpass'],
          [sequelize.fn('sum', sequelize.col('transactions')), 'transactions'],
          [sequelize.fn('sum', sequelize.col('voids')), 'voids'],
          [sequelize.fn('sum', sequelize.col('voids_amount')), 'voids_amount'],
          [sequelize.fn('sum', sequelize.col('refunds')), 'refunds'],
          [sequelize.fn('sum', sequelize.col('refunds_amount')), 'refunds_amount'],
          [sequelize.fn('sum', sequelize.col('discounts')), 'discounts'],
          [sequelize.fn('sum', sequelize.col('discounts_amount')), 'discounts_amount'],
          [sequelize.fn('MONTH', sequelize.col('sales_date')), 'month'],
          [sequelize.fn('YEAR', sequelize.col('sales_date')), 'year'],
        ],
        group: [
          'month',
          'year'
        ],
        where: {
          unit_id: unit_id
        },
        having: {
          year: year
        }
      })
      var i = 0
      const salesMonthly = [];
      salesAggregated.forEach(s => {
        const month = s.dataValues.month
        const from = moment().year(year).month(month - 1).startOf('month')
        const to = moment().year(year).month(month).startOf('month').add(-1, 'day')
        salesMonthly.push({
          id: 1000000 * (year - 2000) + 1000 * unit_id + 500 + i++,
          from: from,
          to: to,
          sale: {
            id: i,
            gross_sales: s.gross_sales,
            tax: s.tax,
            net_sales: s.net_sales,
            net_sales_uber_eats: s.net_sales_uber_eats,
            tax_uber_eats: s.tax_uber_eats,
            net_sales_postmates: s.net_sales_postmates,
            tax_postmates: s.tax_postmates,
            credit_sales: s.credit_sales,
            amex_credit_sales: s.amex_credit_sales,
            master_credit_sales: s.master_credit_sales,
            discover_credit_sales: s.discover_credit_sales,
            visa_credit_sales: s.visa_credit_sales,
            debit_sales: s.debit_sales,
            gift_card_redeem: s.gift_card_redeem,
            gift_card_sold: s.gift_card_sold,
            donations: s.donations,
            cash: s.cash,
            rbi_mobile_app: s.rbi_mobile_app,
            uber_eats: s.uber_eats,
            grubhub: s.grubhub,
            doordash: s.doordash,
            white_label: s.white_label,
            postmates: s.postmates,
            snackpass: s.snackpass,
            transactions: s.transactions,
            voids: s.voids,
            voids_amount: s.voids_amount,
            refunds: s.refunds,
            refunds_amount: s.refunds_amount,
            discounts: s.discounts,
            discounts_amount: s.discounts_amount
          }
        })
      })
      return salesMonthly
    },

    sales_monthly2: async (_, { year, unit_id }) => {
      const from = moment(`${year}0101`, 'YYYYMMDD')
      const to = moment(`${year}1231`, 'YYYYMMDD')
      const salesYear = await models.sale.findAll({
        where: {
          [Op.and]: [
            sequelize.where(sequelize.fn('YEAR', sequelize.col('sales_date')), year),
            { unit_id: unit_id }
          ]
        }
      })

      let count = 0
      let gross_sales = 0
      let tax = 0
      let net_sales = 0
      let net_sales_uber_eats = 0
      let tax_uber_eats = 0
      let net_sales_postmates = 0
      let tax_postmates = 0
      let credit_sales = 0
      let amex_credit_sales = 0
      let master_credit_sales = 0
      let discover_credit_sales = 0
      let visa_credit_sales = 0
      let debit_sales = 0
      let gift_card_redeem = 0
      let gift_card_sold = 0
      let donations = 0
      let cash = 0
      let rbi_mobile_app = 0
      let uber_eats = 0
      let grubhub = 0
      let doordash = 0
      let white_label = 0
      let postmates = 0
      let snackpass = 0
      let transactions = 0
      let voids = 0
      let voids_amount = 0
      let refunds = 0
      let refunds_amount = 0
      let discounts = 0
      let discounts_amount = 0
      let salesWeekly = []

      const dayCount = to.diff(from, 'days') + 2
      const saleByDayIndex = new Array(dayCount).fill(null)
      salesYear.forEach(sales => {
        const days = - from.diff(sales.sales_date, 'days')
        saleByDayIndex[days] = sales
      })
      let missing = 0
      let currentMonth = 0
      saleByDayIndex.forEach((sales, i) => {
        const currentDate = moment(from).add(i, 'days')
        if (currentMonth != currentDate.month()) {
          const currentFrom = moment([year, currentMonth, 1])
          salesWeekly.push({
            id: 1000000 * (year - 2000) + 1000 * unit_id + i,
            from: currentFrom,
            to: moment(currentFrom).endOf('month'),
            missing_count: missing,
            day_count: count,
            sale: count === 0 ? {} : {
              id: i,
              unit_id: unit_id,
              gross_sales: gross_sales,
              tax: tax,
              net_sales: net_sales,
              net_sales_uber_eats: net_sales_uber_eats,
              tax_uber_eats: tax_uber_eats,
              net_sales_postmates: net_sales_postmates,
              tax_postmates: tax_postmates,
              credit_sales: credit_sales,
              amex_credit_sales: amex_credit_sales,
              master_credit_sales: master_credit_sales,
              discover_credit_sales: discover_credit_sales,
              visa_credit_sales: visa_credit_sales,
              debit_sales: debit_sales,
              gift_card_redeem: gift_card_redeem,
              gift_card_sold: gift_card_sold,
              donations: donations,
              cash: cash,
              rbi_mobile_app: rbi_mobile_app,
              uber_eats: uber_eats,
              grubhub: grubhub,
              doordash: doordash,
              white_label: white_label,
              postmates: postmates,
              snackpass: snackpass,
              transactions: transactions,
              voids: voids,
              voids_amount: voids_amount,
              refunds: refunds,
              refunds_amount: refunds_amount,
              discounts: discounts,
              discounts_amount: discounts_amount
            }
          })
          currentMonth = currentDate.month()
          missing = 0
          count = 0
          gross_sales = 0
          tax = 0
          net_sales = 0
          net_sales_uber_eats = 0
          tax_uber_eats = 0
          net_sales_postmates = 0
          tax_postmates = 0
          credit_sales = 0
          amex_credit_sales = 0
          master_credit_sales = 0
          discover_credit_sales = 0
          visa_credit_sales = 0
          debit_sales = 0
          gift_card_redeem = 0
          gift_card_sold = 0
          donations = 0
          cash = 0
          rbi_mobile_app = 0
          uber_eats = 0
          grubhub = 0
          doordash = 0
          white_label = 0
          postmates = 0
          snackpass = 0
          transactions = 0
          voids = 0
          voids_amount = 0
          refunds = 0
          refunds_amount = 0
          discounts = 0
          discounts_amount = 0
        }
        if (sales) {
          count++
          gross_sales += sales.gross_sales
          tax += sales.tax
          net_sales += sales.net_sales
          net_sales_uber_eats += sales.net_sales_uber_eats
          tax_uber_eats += sales.tax_uber_eats
          net_sales_postmates += sales.net_sales_postmates
          tax_postmates += sales.tax_postmates
          credit_sales += sales.credit_sales
          amex_credit_sales += sales.amex_credit_sales
          master_credit_sales += sales.master_credit_sales
          discover_credit_sales += sales.discover_credit_sales
          visa_credit_sales += sales.visa_credit_sales
          debit_sales += sales.debit_sales
          gift_card_redeem += sales.gift_card_redeem
          gift_card_sold += sales.gift_card_sold
          donations += sales.donations
          cash += sales.cash
          rbi_mobile_app += sales.rbi_mobile_app
          uber_eats += sales.uber_eats
          grubhub += sales.grubhub
          doordash += sales.doordash
          white_label += sales.white_label
          postmates += sales.postmates
          snackpass += sales.snackpass
          transactions += sales.transactions
          voids += sales.voids
          voids_amount += sales.voids_amount
          refunds += sales.refunds
          refunds_amount += sales.refunds_amount
          discounts += sales.discounts
          discounts_amount += sales.discounts_amount
        } else {
          missing++
        }
      })
      return salesWeekly
    },

    expense_report: async (_, { unit_id, from, to }) => {
      const saleIds = await models.sale.findAll({
        group: ['id'],
        attributes: [
          'id',
        ],
        where: {
          [Op.and]: [
            {
              sales_date: {
                [Op.gte]: from
              }
            },
            {
              sales_date: {
                [Op.lte]: to
              }
            },
            {
              unit_id: unit_id
            }
          ]
        }
      })
        .map(s => s.id)

      const saleExpenses = await models.sales_expense.findAll({
        where: {
          sale_id: saleIds
        }
      })

      const expensesGroupByCategory = saleExpenses.reduce((result, expense) => ({
        ...result,
        [expense.expense_id]:
          [
            ...(result[expense.expense_id] || []),
            expense,
          ],
      }),
        {},
      );

      const expenseCategories = []
      for (const key in expensesGroupByCategory) {
        const expenses = expensesGroupByCategory[key]
        const total = expenses.redsauce((a, b) => a + b.amount, 0.0)
        if (expenses[0] && expenses[0].expense_title === 'Cash Payroll') {
          expenseCategories.push({
            id: 'Miscellaneous',
            category: 'Miscellaneous',
            total: total,
            expenses: [{
              id: expenses[0].id,
              sale_id: expenses[0].sale_id,
              expense_id: expenses[0].expense_id,
              expense_title: 'Miscellaneous',
              description: 'Miscellaneous',
              amount: total,
              date: expenses[0].date
            }]
          })
        } else {
          expenseCategories.push({
            id: key,
            category: expenses[0].expense_title,
            total: total,
            expenses: expenses
          })
        }
      }

      const total = expenseCategories.reduce((a, b) => a + b.total, 0.0)
      return {
        id: 0,
        from: from,
        to: to,
        total: total,
        expense_categories: expenseCategories
      }
    },

    sales_report: async (_, { unit_id, from, to }) => {
      const sales = await models.sale.findAll({
        attributes: {
          include: [
            [sequelize.fn('DATE', models.sequelize.col('sales_date')), 'sales_date'],
          ]
        },
        having: {
          [Op.and]: [
            {
              sales_date: {
                [Op.gte]: from
              }
            },
            {
              sales_date: {
                [Op.lte]: to
              }
            },
            {
              unit_id: unit_id
            }
          ]
        },
        raw: true
      })
      const idMap = new Map()
      sales.forEach(s => idMap.set(s.id, moment(s.sales_date, 'YYYY-MM-DD')))

      const saleExpenses = await models.sales_expense.findAll({
        where: {
          sale_id: [...idMap.keys()]
        },
        order: [
          ['sale_id', 'ASC']
        ]
      })

      const expensesGroupByCategory = saleExpenses.reduce((result, expense) => ({
        ...result,
        [expense.expense_id]:
          [
            ...(result[expense.expense_id] || []),
            Object.assign(expense, {
              date: idMap.get(expense.sale_id)
            })
          ]
      }),
        {},
      );
      let paymentToMemebersTotal = 0.0
      let paymentToMemebersExpenseCategories = null
      let paymentToMemebersExpenses = []
      const expenseCategories = []
      for (const key in expensesGroupByCategory) {
        const expenses = expensesGroupByCategory[key];
        const total = expenses.reduce((a, b) => a + b.amount, 0.0)
        if (expenses[0] && (expenses[0].expense_title === 'Cash Payroll')) {
          paymentToMemebersTotal += total
          /*paymentToMemebersExpenseCategories = {
            id: 'Payment To Members',
            category: 'Payment To Members',
            total: paymentToMemebersTotal,
            expenses: [{
              id: expenses[0].id,
              sale_id: expenses[0].sale_id,
              expense_id: expenses[0].expense_id,
              expense_title: 'Payment To Members',
              description: 'Payment To Members',
              amount: paymentToMemebersTotal,
              date: expenses[0].date
            }]
          }*/
          paymentToMemebersExpenses = paymentToMemebersExpenses.concat(expenses)
        } else {
          expenseCategories.push({
            id: key,
            category: expenses[0].expense_title,
            total: total,
            expenses: expenses.sort((a, b) => a.date.valueOf() - b.date.valueOf())
          })
        }
      }
      if (paymentToMemebersExpenses.length) {
        paymentToMemebersExpenseCategories = {
          id: 'Payment To Members',
          category: 'Payment To Members',
          total: paymentToMemebersTotal,
          expenses: paymentToMemebersExpenses.sort((a, b) => a.date.valueOf() - b.date.valueOf())
        }
      }
      if (paymentToMemebersExpenseCategories) {
        expenseCategories.unshift(paymentToMemebersExpenseCategories)
      }
      const paymentToMemebers = { total: paymentToMemebersTotal, type: 'PTM' }
      const expenseTotal = expenseCategories.reduce((a, b) => a + b.total, 0.0)
      const saleDeposits = await models.sales_deposit.findAll({
        where: {
          sale_id: [...idMap.keys()]
        },
        order: [
          ['sale_id', 'ASC']
        ]
      })

      const depositsGroupByCategory = saleDeposits.reduce((result, deposit) => ({
        ...result,
        [deposit.bank_id]:
          [
            ...(result[deposit.bank_id] || []),
            Object.assign(deposit, {
              date: idMap.get(deposit.sale_id)
            })
          ],
      }),
        {},
      )

      const depositCategories = []
      for (const key in depositsGroupByCategory) {
        const deposits = depositsGroupByCategory[key];
        const total = deposits.reduce((a, b) => a + b.amount, 0.0)
        depositCategories.push({
          id: key,
          category: deposits[0].bank_title,
          total: total,
          deposits: deposits.sort((a, b) => a.date.valueOf() - b.date.valueOf())
        })
      }

      const depositTotal = depositCategories.reduce((a, b) => a + b.total, 0.0)

      const saleDeliveries = await models.sales_food_delivery.findAll({
        where: {
          sale_id: [...idMap.keys()]
        },
        order: [
          ['sale_id', 'ASC']
        ]
      })

      const deliveriesGroupByCategory = saleDeliveries.reduce((result, delivery) => ({
        ...result,
        [delivery.supplier_id]:
          [
            ...(result[delivery.supplier_id] || []),
            Object.assign(delivery, {
              date: idMap.get(delivery.sale_id)
            })
          ],
      }),
        {},
      );

      const deliveryCategories = []
      for (const key in deliveriesGroupByCategory) {
        const deliveries = deliveriesGroupByCategory[key];
        const total = deliveries.reduce((a, b) => a + b.amount, 0.0)
        deliveryCategories.push({
          id: key,
          category: deliveries[0].supplier_title,
          total: total,
          deliveries: deliveries.sort((a, b) => a.date.valueOf() - b.date.valueOf())
        })
      }

      const deliveriesTotal = deliveryCategories.reduce((a, b) => a + b.total, 0.0)

      const payroll = await models.payroll.findAll({
        attributes: [
          'id',
          'period',
          'status',
          'unit_id',
          'createdAt',
          'updatedAt',
          [sequelize.fn('STR_TO_DATE', sequelize.fn('SUBSTRING_INDEX', sequelize.col('period'), ">", -1), "%Y-%c-%d"), 'payroll_end']
        ],
        where: {
          unit_id: unit_id
        },
        having: {
          [Op.and]: [
            {
              payroll_end: {
                [Op.gte]: from
              }
            },
            {
              payroll_end: {
                [Op.lte]: to
              }
            }
          ]
        }
      })

      const payrollByIdMap = new Map()
      payroll.forEach(p => payrollByIdMap.set(p.id, p))

      const employeePayrolls = await models.employee_payroll.findAll({
        group: ['payroll_id'],
        attributes: [
          'payroll_id',
          [sequelize.fn('sum', sequelize.col('total_expense')), 'total_expense'],
          [sequelize.fn('sum', sequelize.col('hours')), 'hours']
        ],
        where: {
          payroll_id: [...payrollByIdMap.keys()]
        }
      })
        .map(q => {
          const p = payrollByIdMap.get(q.payroll_id)
          const tokens = p.period.split('>')
          return {
            id: p.id,
            period: createPeriod(moment(tokens[0], "YYYY-MM-DD"), moment(tokens[1], "YYYY-MM-DD")),
            amount: q.total_expense,
            hours: q.hours,
            unit_id: p.unit_id,
            status: p.status,
            createdAt: p.createdAt,
            updatedAt: p.updatedAt
          }
        })

      const employeeTypePayrolls = await models.employee_payroll.findAll({
        group: ['employee_type'],
        attributes: [
          'employee_type',
          [sequelize.fn('sum', sequelize.col('total_expense')), 'total_expense']
        ],
        where: {
          payroll_id: payroll.map(p => p.id),
          employee_type: ['Check', 'Salary', 'PTM']
        }
      })
        .map(p => {
          return {
            type: p.employee_type,
            total: p.total_expense
          }
        })
      /*const ptmIndex = employeeTypePayrolls.find(p => p.type === 'PTM')
      if (ptmIndex) {
        employeeTypePayrolls[ptmIndex].total += paymentToMemebers.total
      } else {
        employeeTypePayrolls.push(paymentToMemebers)
      }*/

      const previousTotalCashInHandValue = await previousTotalCashInHand(unit_id, from)
      const totalCashInHandValue = await totalCashInHand(unit_id, to)
      const fromMoment = moment(from)
      const toMoment = moment(to)

      return {
        id: 0,
        from: fromMoment,
        to: toMoment,
        cssh_report: {
          id: 0,
          from: fromMoment,
          to: toMoment,
          total: totalCashInHandValue,
          period_total: totalCashInHandValue - previousTotalCashInHandValue,
          previous_total: previousTotalCashInHandValue
        },
        sales_report: aggregatedSales(unit_id, from, to),
        expense_report: {
          id: 0,
          from: fromMoment,
          to: toMoment,
          total: expenseTotal,
          expense_categories: expenseCategories
        },
        deposit_report: {
          id: 0,
          from: fromMoment,
          to: toMoment,
          total: depositTotal,
          deposit_categories: depositCategories
        },
        delivery_report: {
          id: 0,
          from: fromMoment,
          to: toMoment,
          total: deliveriesTotal,
          delivery_categories: deliveryCategories
        },
        payroll_report: {
          id: 0,
          from: fromMoment,
          to: toMoment,
          total: employeeTypePayrolls.map(p => p.total).reduce((a, b) => a + b, 0),
          employee_type_payrolls: employeeTypePayrolls,
          payrolls: employeePayrolls
        }
      }
    },

    payroll_summary: async (_, { year, unit_id }) => {
      const payrolls = await models.payroll.findAll({
        where: {
          unit_id: unit_id
        },
        order: [
          ['created_at', 'ASC']
        ]
      })

      const start = moment(year + '0101', "YYYYMMDD").startOf('week').add(-1, 'day')
      const payrollSummary = payrolls
        .map(p => {
          const tokens = p.period.split('>')
          return {
            id: p.id,
            unit_id: p.unit_id,
            status: p.status,
            status: p.status,
            createdAt: p.createdAt,
            updatedAt: p.updatedAt,
            range: [moment(tokens[0], "YYYY-MM-DD"), moment(tokens[1], "YYYY-MM-DD")],
          }
        })
        .filter(o => {
          return o.range[0].isAfter(start)
        })
        .map(async o => {
          /*const totals = await models.employee_payroll.findOne({
            attributes: [
              [ sequelize.fn('sum', sequelize.col('hours')), 'hours' ]
              [ sequelize.fn('sum', sequelize.col('total_expense')), 'total_expense' ]
            ],
            where: {
              payroll_id: o.id
            }
          })*/
          const hours = await models.employee_payroll.sum('hours', {
            where: {
              payroll_id: o.id
            }
          })
          const totalExpense = await models.employee_payroll.sum('total_expense', {
            where: {
              payroll_id: o.id
            }
          })
          return {
            period: createPeriod(o.range[0], o.range[1]),
            id: o.id,
            unit_id: o.unit_id,
            hours: hours,
            amount: totalExpense,
            status: o.status,
            createdAt: o.createdAt,
            updatedAt: o.updatedAt,
          }
        })

      /*var maxDate = payrolls
        .map(p => {
          const tokens = p.period.split('>')
          return [moment(tokens[0], "YYYY-MM-DD"), moment(tokens[1], "YYYY-MM-DD")]
        })
        .filter(v => {
          return v[0].year() === year || v[1].year() === year
        })
        .map(
          v => v[1]
        )
        .reduce((max, v) => {
          return (max > v) ? max : v7
        })

      const days = new Date(year, month, 0).getDate()
      for (var day = 1; day <= days; day++) {
        const date = new Date(year, month - 1, day)
        if (!map.has(day)) {
          const missingPayroll = models.sale.build({
            status: -1,
            previous_cash_in_hand: previous_cash_in_hand,
            createdAt: date,
            updatedAt: date
          })
          map.set(day, missingSale)
        }
        else {
          map.get(day).previous_cash_in_hand = previous_cash_in_hand
          previous_cash_in_hand += map.get(day).cash_in_hand
        }
      }
      //console.log(sales)*/
      return [...payrollSummary.values()]
    },

    payroll_summary2: async (_, { year, unit_id }) => {
      const unit = await models.unit.findByPk(unit_id)
      const unitPayrollPeriod = unit.payroll_period
      const unitPayrollStartDay = unit.payroll_start_day

      const payrolls = await models.payroll.findAll({
        where: {
          unit_id: unit_id
        },
        order: [
          [sequelize.fn('STR_TO_DATE', sequelize.fn('SUBSTRING_INDEX', sequelize.col('period'), ">", 1), "%Y-%c-%d"), 'ASC']
        ]
      })
      /*const payrolls = await models.payroll.findAll({
        where: {
          unit_id: unit_id
        },
        order: [
          ['created_at', 'ASC']
        ]
      })*/
      var referenceDate = moment('20161225', "YYYYMMDD").add(unitPayrollStartDay, 'day')
      while (true) {
        if (referenceDate.year() === year) {
          break
        }
        referenceDate = referenceDate.add(unitPayrollPeriod, 'week')
      }
      const yearStart = moment(year + '0101', "YYYYMMDD")
      const previousYearPayrollEnd = referenceDate.add(-1, 'day')
      //yearStart.startOf('week') === yearStart
      //    ? yearStart.add(-1, 'week').add(-1, 'day') : yearStart.startOf('week').add(-1, 'day')

      const payrollWeeks = payrolls
        .map(p => {
          const tokens = p.period.split('>')
          return {
            id: p.id,
            unit_id: p.unit_id,
            status: p.status,
            createdAt: p.createdAt,
            updatedAt: p.updatedAt,
            range: [moment(tokens[0], "YYYY-MM-DD"), moment(tokens[1], "YYYY-MM-DD")],
          }
        })
        .filter(o => o.range[0].isAfter(previousYearPayrollEnd))
        .map(o => {
          return {
            range: o.range,
            period: createPeriod(o.range[0], o.range[1]),
            id: o.id,
            unit_id: o.unit_id,
            hours: 0.0,
            amount: 0.0,
            overtimeHours: 0.0,
            overtimeAmount: 0.0,
            status: o.status,
            createdAt: o.createdAt,
            updatedAt: o.updatedAt,
          }
        })

      for (var i = 0; i < payrollWeeks.length; i++) {
        payrollWeeks[i].hours = 0 /*await models.employee_payroll.sum('hours', {
          where: {
            payroll_id: payrollWeeks[i].id
          }
        })*/
        payrollWeeks[i].amount = 0 /*await models.employee_payroll.sum('total_expense', {
          where: {
            payroll_id: payrollWeeks[i].id
          }
        })*/
      }

      const today = moment()
      var payrollPeriodWeeks = new Array(unitPayrollPeriod)
      var payrollSummary = []
      var endOfWeek = previousYearPayrollEnd
      var i = 0, j = 0, k = 0
      while (true) {
        if (j < unitPayrollPeriod) {
          //console.log(i < payrollWeeks.length ? endOfWeek.diff(payrollWeeks[i].range[0], 'days') : -99)
          //const diff = i < payrollWeeks.length ? endOfWeek.diff(payrollWeeks[i].range[0], 'days') : 100
          //console.log(endOfWeek.format('YYYY-MM-DD') + " - " + payrollWeeks[i].range[0].format('YYYY-MM-DD') + ": " + diff)
          //if (diff == -1 || (i == 0 && diff > -4 && diff < 4)) {
          if (i < payrollWeeks.length && endOfWeek.diff(payrollWeeks[i].range[0], 'days') === -1) {
            payrollPeriodWeeks[j++] = payrollWeeks[i]
            endOfWeek = payrollWeeks[i].range[1]
            i++
          }
          else {
            const startOfWeek = endOfWeek.clone().add(1, 'day')
            endOfWeek = endOfWeek.clone().add(1, 'week')
            payrollPeriodWeeks[j++] = {
              id: -(1000000 * (year - 2000) + 1000 * unit_id + k),
              range: [startOfWeek, endOfWeek],
              period: createPeriod(startOfWeek, endOfWeek),
              hours: 0.0,
              amount: 0.0,
              overtimeHours: 0.0,
              overtimeAmount: 0.0,
              status: endOfWeek <= today ? 'Run' : ''
            }
          }
        }
        else {
          var status
          if (payrollPeriodWeeks.every(p => p.status === 'Finalized')) {
            status = 'Finalized'
          }
          else if (payrollPeriodWeeks.some(p => p.status === '')) {
            status = ''
          }
          else if (payrollPeriodWeeks.some(p => p.status === 'Run')) {
            status = 'Run'
          }
          else {
            status = 'Closed'
          }
          payrollSummary.push({
            unit_id: unit_id,
            period: createPeriod(payrollPeriodWeeks[0].range[0], payrollPeriodWeeks[j - 1].range[1]),
            hours: payrollPeriodWeeks.map(p => p.hours).reduce((a, b) => a + b, 0.0),
            amount: payrollPeriodWeeks.map(p => p.amount).reduce((a, b) => a + b, 0.0),
            payroll_weeks: payrollPeriodWeeks,
            status: status
          })
          payrollPeriodWeeks = new Array(unitPayrollPeriod)
          j = 0
          if (endOfWeek.year() > year) {
            break
          }
        }
        k++
      }

      return payrollSummary
    },

    payroll_summary3: async (_, { year, unit_id }) => {
      const today = moment()
      const unit = await models.unit.findByPk(unit_id)
      const unitPayrollPeriod = unit.payroll_period
      const unitPayrollStartDay = unit.payroll_start_day

      const payrolls = await models.payroll.findAll({
        attributes: {
          include: [
            [sequelize.fn('STR_TO_DATE', sequelize.fn('SUBSTRING_INDEX', sequelize.col('period'), ">", 1), "%Y-%c-%d"), 'payroll_start'],
            [sequelize.fn('STR_TO_DATE', sequelize.fn('SUBSTRING_INDEX', sequelize.col('period'), ">", -1), "%Y-%c-%d"), 'payroll_end'],
            [sequelize.fn('YEAR', sequelize.fn('STR_TO_DATE', sequelize.fn('SUBSTRING_INDEX', sequelize.col('period'), ">", -1), "%Y-%c-%d")), 'year']
          ]
        },
        where: {
          [Op.or]: [
            {
              [Op.and]: [
                sequelize.where(sequelize.fn('YEAR', sequelize.fn('STR_TO_DATE', sequelize.fn('SUBSTRING_INDEX', sequelize.col('period'), ">", -1), "%Y-%c-%d")), year),
                { unit_id: unit_id }
              ]
            },
            {
              [Op.and]: [
                sequelize.where(sequelize.fn('YEAR', sequelize.fn('STR_TO_DATE', sequelize.fn('SUBSTRING_INDEX', sequelize.col('period'), ">", 1), "%Y-%c-%d")), year),
                sequelize.where(sequelize.fn('YEAR', sequelize.fn('STR_TO_DATE', sequelize.fn('SUBSTRING_INDEX', sequelize.col('period'), ">", -1), "%Y-%c-%d")), year + 1),
                { unit_id: unit_id }
              ]
            }
          ]
        },
        order: [
          [sequelize.fn('STR_TO_DATE', sequelize.fn('SUBSTRING_INDEX', sequelize.col('period'), ">", 1), "%Y-%c-%d"), 'ASC']
        ]
      })
      const yearStartDate = moment(year, "YYYY").startOf('year')
      var referenceDate = moment('20161225', "YYYYMMDD").add(unitPayrollStartDay, 'day')
      while (true) {
        if (referenceDate.year() === year) {
          break
        }
        referenceDate = referenceDate.add(1, 'week')
      }
      const previousYearPayrollEnd = referenceDate.add(-1, 'day')

      const payrollWeeks = payrolls
        .map(p => {
          const range = [moment(p.dataValues.payroll_start, "YYYY-MM-DD"), moment(p.dataValues.payroll_end, "YYYY-MM-DD")]
          return {
            id: p.id,
            unit_id: p.unit_id,
            status: p.status,
            hours: 0.0,
            amount: 0.0,
            overtimeHours: 0.0,
            overtimeAmount: 0.0,
            createdAt: p.createdAt,
            updatedAt: p.updatedAt,
            range: range,
            period: createPeriod(range[0], range[1])
          }
        })
        .filter(o => o.range[0].isAfter(previousYearPayrollEnd))

      let yearPayrollStart = previousYearPayrollEnd.clone().add(1, 'days').clone()
      if (payrolls.length === 0) {
        let startOfWeek = yearPayrollStart.clone()
        if (startOfWeek.day() !== unitPayrollStartDay) {
          startOfWeek = startOfWeek.clone().add(unitPayrollStartDay - startOfWeek.day() - 7, 'days')
        }
        let endOfWeek = startOfWeek.clone().add(6, 'days')
        while (endOfWeek.year() === year) {
          const range = [startOfWeek, endOfWeek]
          payrollWeeks.push({
            id: -(1000000 * (year - 2000) + 1000 * unit_id + payrollWeeks.length),
            unit_id: unit_id,
            status: endOfWeek <= today ? 'Run' : '',
            hours: 0.0,
            amount: 0.0,
            overtimeHours: 0.0,
            overtimeAmount: 0.0,
            createdAt: moment(),
            updatedAt: moment(),
            range: range,
            period: createPeriod(range[0], range[1])
          })
          startOfWeek = startOfWeek.clone().add(1, 'week')
          endOfWeek = endOfWeek.clone().add(1, 'week')
        }
      }

      if (payrollWeeks.length > 0 && payrollWeeks[0].range[0].diff(yearPayrollStart, 'days') > 0) {
        let startOfWeek = payrollWeeks[0].range[0].clone().subtract(1, 'week')
        let endOfWeek = payrollWeeks[0].range[1].clone().subtract(1, 'week')
        while (endOfWeek.year() === year) {
          const range = [startOfWeek, endOfWeek]
          payrollWeeks.unshift({
            id: -(1000000 * (year - 2000) + 1000 * unit_id + payrollWeeks.length),
            unit_id: unit_id,
            status: endOfWeek <= today ? 'Run' : '',
            hours: 0.0,
            amount: 0.0,
            overtimeHours: 0.0,
            overtimeAmount: 0.0,
            createdAt: moment(),
            updatedAt: moment(),
            range: range,
            period: createPeriod(range[0], range[1])
          })
          startOfWeek = startOfWeek.clone().subtract(1, 'week')
          endOfWeek = endOfWeek.clone().subtract(1, 'week')
        }
      }

      for (let i = 0; i < payrollWeeks.length; i++) {
        payrollWeeks[i].hours = 0 /*await models.employee_payroll.sum('hours', {
          where: {
            payroll_id: payrollWeeks[i].id
          }
        })*/
        payrollWeeks[i].amount = 0 /*await models.employee_payroll.sum('total_expense', {
          where: {
            payroll_id: payrollWeeks[i].id
          }
        })*/
      }

      let payrollPeriodWeeks = new Array(unitPayrollPeriod)
      let payrollSummary = []
      let endOfWeek = previousYearPayrollEnd
      let currentEndOfWeek = payrollWeeks.length == 0 ? endOfWeek.clone().add(1, 'day') : payrollWeeks[0].range[1]
      let i = 0, j = 0, k = 0
      while (true) {
        if (j < unitPayrollPeriod) {
          if ((i < payrollWeeks.length)
            && (payrollWeeks[i].range[0].diff(endOfWeek, 'days') === 1 || payrollWeeks[i].range[0].diff(endOfWeek, 'days') === -1)) {
            payrollPeriodWeeks[j++] = payrollWeeks[i]
            endOfWeek = payrollWeeks[i].range[1]
            i++
          } else {
            const startOfWeek = endOfWeek.clone().add(1, 'day')
            if (i < payrollWeeks.length) {
              endOfWeek = endOfWeek.clone().add(1, 'week')
              const diff = payrollWeeks[i].range[0].diff(endOfWeek, 'days')
              if (diff > 1 && diff < 6) {
                endOfWeek = endOfWeek.clone().add(diff - 1, 'days')
              } else if (diff < 1) {
                endOfWeek = payrollWeeks[i].range[0].clone().subtract(1, 'days')
              }
            } else {
              endOfWeek = endOfWeek.clone().add(1, 'week')
              const day = (endOfWeek.day() + 1) % 7
              endOfWeek = endOfWeek.clone().add(unitPayrollStartDay - day, 'days')
            }
            payrollPeriodWeeks[j++] = {
              id: -(1000000 * (year - 2000) + 1000 * unit_id + k),
              range: [startOfWeek, endOfWeek],
              period: createPeriod(startOfWeek, endOfWeek),
              hours: 0.0,
              amount: 0.0,
              overtimeHours: 0.0,
              overtimeAmount: 0.0,
              status: endOfWeek <= today ? 'Run' : ''
            }
          }
        } else {
          let status
          if (payrollPeriodWeeks.every(p => p.status === 'Finalized')) {
            status = 'Finalized'
          }
          else if (payrollPeriodWeeks.some(p => p.status === '')) {
            status = ''
          }
          else if (payrollPeriodWeeks.some(p => p.status === 'Run')) {
            status = 'Run'
          }
          else {
            status = 'Closed'
          }
          payrollSummary.push({
            unit_id: unit_id,
            period: createPeriod(payrollPeriodWeeks[0].range[0], payrollPeriodWeeks[j - 1].range[1]),
            hours: payrollPeriodWeeks.map(p => p.hours).reduce((a, b) => a + b, 0.0),
            amount: payrollPeriodWeeks.map(p => p.amount).reduce((a, b) => a + b, 0.0),
            payroll_weeks: payrollPeriodWeeks,
            status: status
          })
          payrollPeriodWeeks = new Array(unitPayrollPeriod)
          j = 0
          if (endOfWeek.year() > year) {
            break
          }
        }
        k++
      }

      return payrollSummary
    },

    unit_payrolls: async (_, { unit_id }) => {
      const unit = await models.unit.findByPk(unit_id)
      const unitPayrollPeriod = unit.payroll_period
      const payrolls = await models.payroll.findAll({
        where: {
          unit_id: unit_id
        },
        order: [
          [sequelize.fn('STR_TO_DATE', sequelize.fn('SUBSTRING_INDEX', sequelize.col('period'), ">", 1), "%Y-%c-%d"), 'ASC']
        ]
      })

      const payrollWeeks = payrolls
        .map(p => {
          const tokens = p.period.split('>')
          return {
            id: p.id,
            unit_id: p.unit_id,
            status: p.status,
            createdAt: p.createdAt,
            updatedAt: p.updatedAt,
            range: [moment(tokens[0], "YYYY-MM-DD"), moment(tokens[1], "YYYY-MM-DD")],
          }
        })
        .map(o => {
          return {
            range: o.range,
            period: createPeriod(o.range[0], o.range[1]),
            id: o.id,
            unit_id: o.unit_id,
            hours: 0.0,
            amount: 0.0,
            status: o.status,
            createdAt: o.createdAt,
            updatedAt: o.updatedAt,
          }
        })

      /*for (var i = 0; i < payrollWeeks.length; i++) {
        payrollWeeks[i].hours = await models.employee_payroll.sum('hours', {
          where: {
            payroll_id: payrollWeeks[i].id
          }
        })
        payrollWeeks[i].amount = await models.employee_payroll.sum('total_expense', {
          where: {
            payroll_id: payrollWeeks[i].id
          }
        })
      }*/

      const employeePayrollAggregated = await models.employee_payroll.findAll({
        attributes: [
          'payroll_id',
          [sequelize.fn('sum', sequelize.col('hours')), 'hours'],
          [sequelize.fn('sum', sequelize.col('total_expense')), 'total_expense'],
        ],
        group: [
          'payroll_id'
        ],
        where: {
          payroll_id: payrollWeeks.map(p => p.id)
        }
      })

      for (var i = 0; i < payrollWeeks.length; i++) {
        if (i < employeePayrollAggregated.length) {
          payrollWeeks[i].hours = employeePayrollAggregated[i].hours
          payrollWeeks[i].amount = employeePayrollAggregated[i].amount
        } else {
          payrollWeeks[i].hours = 0.0
          payrollWeeks[i].amount = 0.0
        }
      }

      var payrollPeriodWeeks = new Array(unitPayrollPeriod)
      var payrollSummary = []
      var i = 0, j = 0
      while (true) {
        if (j < unitPayrollPeriod && i < payrollWeeks.length) {
          payrollPeriodWeeks[j++] = payrollWeeks[i++]
        }
        else {
          var status
          if (payrollPeriodWeeks.every(p => p.status === 'Finalized')) {
            status = 'Finalized'
          }
          else if (payrollPeriodWeeks.some(p => p.status === '')) {
            status = ''
          }
          else if (payrollPeriodWeeks.some(p => p.status === 'Run')) {
            status = 'Run'
          }
          else {
            status = 'Closed'
          }
          payrollSummary.push({
            unit_id: unit_id,
            period: createPeriod(payrollPeriodWeeks[0].range[0], payrollPeriodWeeks[j - 1].range[1]),
            hours: payrollPeriodWeeks.map(p => p.hours).reduce((a, b) => a + b, 0.0),
            amount: payrollPeriodWeeks.map(p => p.amount).reduce((a, b) => a + b, 0.0),
            payroll_weeks: payrollPeriodWeeks,
            status: status
          })
          payrollPeriodWeeks = new Array(unitPayrollPeriod)
          if (i >= payrollWeeks.length) {
            break
          }
          j = 0
        }
      }
      return payrollSummary
    },

    employee_changes: (_, { unit_id }) => {
      return models.employee_change.findAll({
        where: {
          [Op.and]: [
            {
              deleted_at: {
                [Op.eq]: null
              }
            },
            {
              unit_id: unit_id
            }
          ]
        }
      })
    },

    employee_payrolls_by_payroll_id: (_, { payroll_id }) => {
      return models.employee_payroll.findAll({
        where: {
          payroll_id: payroll_id
        }
      })
    },

    employee_payrolls_aggregated: async (_, { payroll_ids }) => {
      const unit = await models.payroll.findAll({
        group: ['unit_id'],
        attributes: [
          'unit_id',
        ],
        where: {
          id: payroll_ids
        }
      })
      const unitId = unit[0].unit_id
      const employee_payrolls_aggregated = await models.employee_payroll.findAll({
        group: ['employee_id'],
        attributes: [
          'id',
          'employee_id',
          'employee_type',
          'payroll_id',
          [sequelize.fn('avg', sequelize.col('wages')), 'wages'],
          [sequelize.fn('sum', sequelize.col('hours')), 'hours'],
          [sequelize.fn('sum', sequelize.col('gross_wages')), 'gross_wages'],
          [sequelize.fn('avg', sequelize.col('employer_contribution')), 'employer_contribution'],
          [sequelize.fn('sum', sequelize.col('employer_liability')), 'employer_liability'],
          [sequelize.fn('sum', sequelize.col('total_expense')), 'total_expense'],
        ],
        where: {
          payroll_id: payroll_ids
        }
      })

      const hours = await models.employee_payroll.findAll({
        attributes: [
          'id',
          'employee_id',
          'hours',
          'gross_wages',
        ],
        where: {
          payroll_id: payroll_ids
        }
      })
      return employee_payrolls_aggregated.map(p => {
        const employeeHours = hours.filter(h => h.employee_id === p.employee_id)
        return {
          id: p.id,
          employee_id: p.employee_id,
          employee_type: p.employee_type,
          payroll_id: p.payroll_id,
          payroll_ids: payroll_ids,
          weekly_hours: employeeHours.map(h => h.hours),
          weekly_gross_wages: employeeHours.map(h => h.gross_wages),
          wages: p.wages,
          hours: p.hours,
          overtime: employeeHours.map(h => h.hours > 40.0 ? h.hours - 40.0 : 0.0).reduce((a, b) => a + b, 0.0),
          gross_wages: p.gross_wages,
          employer_contribution: p.employer_contribution,
          employer_liability: p.employer_liability,
          total_expense: p.total_expense,
          unit_id: unitId
        }
      })
    },

    sale_comparison: (_, args) => {
      const unitId = args.unit_id
      const period = args.period
      const year1 = args.year1
      const month1 = args.month1
      const year2 = args.year2
      const month2 = args.month2
      if (period == 'MONTH') {
        return models.sale.findAll({
          group: ['month'],
          attributes: [
            [sequelize.fn('MONTH', sequelize.col('sales_date')), 'month'],
            [sequelize.fn('sum', sequelize.col('sales_date')), 'net_sales']
          ],
          where: {
            [Op.and]: [
              sequelize.where(sequelize.fn('MONTH', sequelize.col('sales_date')), month1),
              sequelize.where(sequelize.fn('YEAR', sequelize.col('sales_date')), year1),
              { unit_id: unitId }
            ]
          }
        })
      }
      else if (period == 'WEEKLY') {
        return models.sale.findAll({
          group: ['week'],
          attributes: [
            [sequelize.fn('WEEK', sequelize.col('sales_date')), 'week'],
            [sequelize.fn('sum', sequelize.col('net_sales')), 'net_sales']
          ],
          where: {
            [Op.and]: [
              sequelize.where(sequelize.fn('YEAR', sequelize.col('sales_date')), year1),
              { unit_id: unitId }
            ]
          }
        })
      }
      return models.sale.findAll({
        attributes: [
          [sequelize.fn('DAY', sequelize.col('sales_date')), 'day']
        ],
        where: {
          [Op.and]: [
            sequelize.where(sequelize.fn('MONTH', sequelize.col('sales_date')), month1),
            sequelize.where(sequelize.fn('YEAR', sequelize.col('sales_date')), year1),
            { unit_id: unitId }
          ]
        }
      })
    },

    sales_expense: (_, { sale_expense_id }) => models.sales_expense.findByPk(sale_expense_id),
    sales_expenses: (_, { sale_id }) => models.sales_expense.findAll({
      where: {
        sale_id: sale_id
      }
    }),

    sales_food_delivery: (_, { delivery_id }) => models.sales_food_delivery.findByPk(delivery_id),
    sales_food_deliveries: (_, { sale_id }) => models.sales_food_delivery.findAll({
      where: {
        sale_id: sale_id
      }
    }),

    sales_years: (_) => models.sale.findAll({
      attributes: [
        'createdAt',
        [sequelize.fn('YEAR', sequelize.col('sales_date')), 'year']
      ],
      group: [
        'year'
      ]
    }).map(s => moment(s.createdAt).year()).filter(y => y >= 2017),

    supplier: (_, { supplier_id }) => models.supplier.findByPk(supplier_id),
    suppliers: (_) => models.supplier.findAll({
      order: [
        ['name', 'ASC']
      ]
    }),

    user_dashboard: async (_, { user_id }) => {
      const unitIds = await models.unit_user.findAll({
        where: {
          user_id: user_id
        }
      }).map(u => u.unit_id)

      const to = moment().subtract(1, 'years')
      const from = moment().subtract(1, 'years').subtract(30, "days");

      const saleIds = await models.sale.findAll({
        attributes: [
          'id',
        ],
        where: {
          [Op.and]: [
            {
              unit_id: unitIds
            },
            {
              sales_date: {
                [Op.gte]: from
              }
            },
            {
              sales_date: {
                [Op.lte]: to
              }
            }
          ]
        }
      }).map(s => s.id)

      const sales = await models.sale.findAll({
        group: ['sales_date'],
        attributes: [
          [sequelize.fn('sum', sequelize.col('net_sales')), 'net_sales'],
          [sequelize.fn('sum', sequelize.col('transactions')), 'transactions'],
        ],
        where: {
          id: saleIds
        }
      })

      const expenses = await models.sales_expense.findAll({
        group: ['sale_id'],
        attributes: [
          [sequelize.fn('sum', sequelize.col('amount')), 'amount'],
        ],
        where: {
          [Op.and]: [
            {
              sale_id: saleIds
            }
          ]
        }
      })

      const deposits = await models.sales_deposit.findAll({
        group: ['sale_id'],
        attributes: [
          [sequelize.fn('sum', sequelize.col('amount')), 'amount'],
        ],
        where: {
          [Op.and]: [
            {
              sale_id: saleIds
            }
          ]
        }
      })

      const deliveries = await models.sales_food_delivery.findAll({
        group: ['sale_id'],
        attributes: [
          [sequelize.fn('sum', sequelize.col('amount')), 'amount'],
        ],
        where: {
          [Op.and]: [
            {
              sale_id: saleIds
            }
          ]
        }
      })

      const payrolls = await models.payroll.findAll({
        attributes: [
          'id',
          'period',
          'status',
          'unit_id',
          [sequelize.fn('STR_TO_DATE', sequelize.fn('SUBSTRING_INDEX', sequelize.col('period'), ">", -1), "%Y-%c-%d"), 'payroll_end']
        ],
        where: {
          unit_id: {
            [Op.and]: unitIds
          }
        },
        having: {
          [Op.and]: [
            {
              payroll_end: {
                [Op.gte]: from.format("YYYY-MM-DD")
              }
            },
            {
              payroll_end: {
                [Op.lte]: to.format("YYYY-MM-DD")
              }
            }
          ]
        }
      })

      const gross_wages = await models.employee_payroll.findAll({
        group: ['payroll_id'],
        attributes: [
          [sequelize.fn('sum', sequelize.col('gross_wages')), 'gross_wages'],
        ],
        where: {
          [Op.and]: [
            {
              payroll_id: payrolls.map(s => s.id)
            }
          ]
        }
      })

      return {
        total_stores: unitIds.length,
        total_net_sales_for_last_30_days: sales.map(s => s.net_sales).reduce((a, b) => a + b, 0.0),
        total_transactions_for_last_30_days: sales.map(s => s.transactions).reduce((a, b) => a + b, 0.0),
        total_expenses_for_last_30_days: expenses.map(e => e.amount).reduce((a, b) => a + b, 0.0),
        total_deposits_for_last_30_days: deposits.map(e => e.amount).reduce((a, b) => a + b, 0.0),
        total_deliveries_for_last_30_days: deliveries.map(e => e.amount).reduce((a, b) => a + b, 0.0),
        total_wages_for_last_30_days: gross_wages.map(p => p.gross_wages).reduce((a, b) => a + b, 0.0),
        daily_net_sales_for_last_30_days: sales.map(s => s.net_sales),
        daily_transactions_for_last_30_days: sales.map(s => s.transactions),
        payrolls_for_last_30_days: gross_wages.map(p => p.gross_wages)
      }
    },

    user_dashboard2: async (_, { user_id }) => {
      const to = moment().subtract(1, 'years')
      const from = moment().subtract(1, 'years').subtract(30, "days");

      return {
        last_month: getUserDashboard(user_id, from, to),
        before_last_month: getUserDashboard(user_id, from, to)
      }
    },

    user_summary: (_, { user_id, from, to }) => {
      return getUserDashboard(user_id, moment(from), moment(to))
    },

    user_summary_by_month: (_, { user_id, from, to }) => {
      return getUserSummaryByMonth(user_id, moment.utc(from), moment.utc(to))
    },

    user_missing_sales: async (_, { user_id }) => {
      let unitMap = new Map()
      const userUnitIds = await models.unit_user.findAll({
        where: {
          user_id: user_id
        }
      }).map(u => u.unit_id)

      const userUnits = await models.unit.findAll({
        where: {
          id: {
            [Op.in]: userUnitIds
          }
        }
      })
      userUnits.forEach(u => unitMap.set(u.id, u))

      const missing = []
      for (let i = 1; i < 3; i++) {
        let date = moment().subtract(i, 'days')
        const saleUnits = await models.sales.findAll({
          attributes: [
            'unit_id',
          ],
          where: {
            [Op.and]: [
              {
                unit_id: userUnitIds
              },
              {
                sales_date: date.format('YYYY-MM-DD')
              }
            ]
          }
        })
        let saleUnitMap = new Map()
        saleUnits.forEach(s => saleUnitMap.set(s.unit_id, s.unit_id))
        for (const [unitId, unit] of unitMap.entries()) {
          if (!saleUnitMap.has(unitId)) {
            missing.push({
              date: date,
              unit: unit
            })
          }
        }
      }

      return missing
    },

    user_missing_payrolls: async (_, { user_id }) => {
      let unitMap = new Map()
      const userUnitIds = await models.unit_user.findAll({
        where: {
          user_id: user_id
        }
      }).map(u => u.unit_id)

      const userUnits = await models.unit.findAll({
        where: {
          id: {
            [Op.in]: userUnitIds
          }
        }
      })
      userUnits.forEach(u => unitMap.set(u.id, u))

      const missing = []
      const from = moment().subtract(7, 'days')
      const to = moment()

      for (const unit of userUnits) {
        const periods = payrollPeriods(moment().year(), unit.payroll_start_day, unit.payroll_period)
        for (const period of periods) {
          if (from.isBefore(period.end) && to.isAfter(period.end)) {
            const payroll = await models.payroll.findOne({
              attributes: [
                'id',
              ],
              where: {
                [Op.and]: [
                  {
                    unit_id: unit.id
                  },
                  {
                    period: period.period
                  }
                ]
              }
            })
            if (!payroll) {
              missing.push({
                unit: unit,
                period: period
              })
            }
          }
        }
      }

      return missing
    },

    user_unit_summaries: async (_, { user_id, from, to }) => {
      const unitIds = await models.unit_user.findAll({
        where: {
          user_id: user_id
        }
      }).map(u => u.unit_id)

      const unitPayroll = new Map()
      unitIds.forEach(id => unitPayroll.set(id, {
        unit_id: id,
        sale_days: 0,
        gross_sales: 0.0,
        tax: 0.0,
        net_sales: 0.0,
        net_sales_uber_eats: 0.0,
        tax_uber_eats: 0.0,
        net_sales_postmates: 0.0,
        tax_postmates: 0.0,
        credit_sales: 0.0,
        amex_credit_sales: 0.0,
        master_credit_sales: 0.0,
        discover_credit_sales: 0.0,
        visa_credit_sales: 0.0,
        debit_sales: 0.0,
        gift_card_redeem: 0.0,
        gift_card_sold: 0.0,
        donations: 0.0,
        cash: 0.0,
        rbi_mobile_app: 0.0,
        uber_eats: 0.0,
        grubhub: 0.0,
        doordash: 0.0,
        white_label: 0.0,
        postmates: 0.0,
        snackpass: 0.0,
        transactions: 0.0,
        voids: 0.0,
        voids_amount: 0.0,
        refunds: 0.0,
        refunds_amount: 0.0,
        discounts: 0.0,
        discounts_amount: 0.0,
        check: 0.0,
        salary: 0.0,
        cash_pay: 0.0,
        expenses: 0.0,
        deliveries: 0.0,
        deposits: 0.0
      }))

      const saleByUnit = new Map()
      const periodSales = await models.sale.findAll({
        having: {
          [Op.and]: [
            {
              sales_date: {
                [Op.gte]: from
              }
            },
            {
              sales_date: {
                [Op.lte]: to
              }
            },
            {
              unit_id: unitIds
            }
          ]
        },
        raw: true
      })

      periodSales.forEach(s => {
        saleByUnit.set(s.id, s.unit_id)
        unitPayroll.get(s.unit_id).sale_days++
      })

      periodSales.forEach(s => {
        const unitId = saleByUnit.get(s.id)
        unitPayroll.get(unitId).gross_sales += s.gross_sales
        unitPayroll.get(unitId).tax += s.tax
        unitPayroll.get(unitId).net_sales += s.net_sales
        unitPayroll.get(unitId).net_sales_uber_eats += s.net_sales_uber_eats
        unitPayroll.get(unitId).tax_uber_eats += s.tax_uber_eats
        unitPayroll.get(unitId).net_sales_postmates += s.net_sales_postmates
        unitPayroll.get(unitId).tax_postmates += s.tax_postmates
        unitPayroll.get(unitId).credit_sales += s.credit_sales
        unitPayroll.get(unitId).amex_credit_sales += s.amex_credit_sales
        unitPayroll.get(unitId).master_credit_sales += s.master_credit_sales
        unitPayroll.get(unitId).discover_credit_sales += s.discover_credit_sales
        unitPayroll.get(unitId).visa_credit_sales += s.visa_credit_sales
        unitPayroll.get(unitId).debit_sales += s.debit_sales
        unitPayroll.get(unitId).gift_card_redeem += s.gift_card_redeem
        unitPayroll.get(unitId).gift_card_sold += s.gift_card_sold
        unitPayroll.get(unitId).donations += s.donations
        unitPayroll.get(unitId).cash += s.cash
        unitPayroll.get(unitId).rbi_mobile_app += s.rbi_mobile_app
        unitPayroll.get(unitId).uber_eats += s.uber_eats
        unitPayroll.get(unitId).grubhub += s.grubhub
        unitPayroll.get(unitId).doordash += s.doordash
        unitPayroll.get(unitId).white_label += s.white_label
        unitPayroll.get(unitId).postmates += s.postmates
        unitPayroll.get(unitId).snackpass += s.snackpass
        unitPayroll.get(unitId).voids += s.voids
        unitPayroll.get(unitId).voids_amount += s.voids_amount
        unitPayroll.get(unitId).refunds += s.refunds
        unitPayroll.get(unitId).refunds_amount += s.refunds_amount
        unitPayroll.get(unitId).discounts += s.discounts
        unitPayroll.get(unitId).discounts_amount += s.discounts_amount
      })

      const expenses = await models.sales_expense.findAll({
        group: [
          'sale_id',
          'expense_id'
        ],
        attributes: [
          'sale_id',
          'expense_id',
          [sequelize.fn('sum', sequelize.col('amount')), 'amount'],
        ],
        where: {
          [Op.and]: [
            {
              sale_id: [...saleByUnit.keys()]
            }
          ]
        },
        logging: false
      })
      expenses.forEach(s => {
        const unitId = saleByUnit.get(s.sale_id)
        if (s.expense_id === 2) {
          unitPayroll.get(unitId).cash_pay += s.amount
        } else {
          unitPayroll.get(unitId).expenses += s.amount
        }
      })

      const deposits = await models.sales_deposit.findAll({
        group: ['sale_id'],
        attributes: [
          'sale_id',
          [sequelize.fn('SUM', sequelize.col('amount')), 'amount']
        ],
        where: {
          sale_id: [...saleByUnit.keys()]
        },
        logging: false
      })
      deposits.forEach(s => {
        const unitId = saleByUnit.get(s.sale_id)
        unitPayroll.get(unitId).deposits += s.amount
      })

      const deliveries = await models.sales_food_delivery.findAll({
        group: ['sale_id'],
        attributes: [
          'sale_id',
          [sequelize.fn('sum', sequelize.col('amount')), 'amount'],
        ],
        where: {
          [Op.and]: [
            {
              sale_id: [...saleByUnit.keys()]
            }
          ]
        },
        logging: false
      })
      deliveries.forEach(s => {
        const unitId = saleByUnit.get(s.sale_id)
        unitPayroll.get(unitId).deliveries += s.amount
      })

      const payrolls = await models.payroll.findAll({
        attributes: [
          'id',
          'period',
          'status',
          'unit_id',
          [sequelize.fn('STR_TO_DATE', sequelize.fn('SUBSTRING_INDEX', sequelize.col('period'), ">", -1), "%Y-%c-%d"), 'payroll_end']
        ],
        where: {
          unit_id: unitIds
        },
        having: {
          [Op.and]: [
            {
              payroll_end: {
                [Op.gte]: from
              }
            },
            {
              payroll_end: {
                [Op.lte]: to
              }
            }
          ]
        },
        logging: false
      })
      const payrollByUnit = new Map()
      payrolls.forEach(p => payrollByUnit.set(p.id, p.unit_id))

      const totalExpense = await models.employee_payroll.findAll({
        group: ['payroll_id', 'employee_type'],
        attributes: [
          'payroll_id',
          'employee_type',
          [sequelize.fn('sum', sequelize.col('total_expense')), 'total_expense'],
        ],
        where: {
          [Op.and]: [
            {
              payroll_id: payrolls.map(s => s.id)
            }
          ]
        }
      })

      totalExpense.forEach(wages => {
        const unitId = payrollByUnit.get(wages.payroll_id)
        if (wages.employee_type === 'Salary') {
          unitPayroll.get(unitId).salary += wages.total_expense
        } else if (wages.employee_type === 'Check') {
          unitPayroll.get(unitId).check += wages.total_expense
        }
      })

      return [...unitPayroll.values()]
    },

    user_unit_summaries_weekly: async (_, { user_id, week_of }) => {
      const unitIds = await models.unit_user.findAll({
        where: {
          user_id: user_id
        }
      }).map(u => u.unit_id)

      const unitPayroll = new Map()
      unitIds.forEach(id => unitPayroll.set(id, {
        unit_id: id,
        sale_days: 0,
        gross_sales: 0.0,
        tax: 0.0,
        net_sales: 0.0,
        net_sales_uber_eats: 0.0,
        tax_uber_eats: 0.0,
        net_sales_postmates: 0.0,
        tax_postmates: 0.0,
        credit_sales: 0.0,
        amex_credit_sales: 0.0,
        master_credit_sales: 0.0,
        discover_credit_sales: 0.0,
        visa_credit_sales: 0.0,
        debit_sales: 0.0,
        gift_card_redeem: 0.0,
        gift_card_sold: 0.0,
        donations: 0.0,
        cash: 0.0,
        rbi_mobile_app: 0.0,
        uber_eats: 0.0,
        grubhub: 0.0,
        doordash: 0.0,
        white_label: 0.0,
        postmates: 0.0,
        snackpass: 0.0,
        transactions: 0,
        voids: 0,
        voids_amount: 0.0,
        refunds: 0,
        refunds_amount: 0.0,
        discounts: 0,
        discounts_amount: 0.0,
        check: 0.0,
        salary: 0.0,
        cash_pay: 0.0,
        expenses: 0.0,
        deliveries: 0.0,
        deposits: 0.0
      }))

      const weekOf = moment(week_of, 'YYYY-MM-DD').endOf("week").subtract(2, 'day').format('YYYY-MM-DD')
      const payrolls = await models.payroll.findAll({
        attributes: [
          'id',
          'period',
          'status',
          'unit_id',
          [sequelize.fn('STR_TO_DATE', sequelize.fn('SUBSTRING_INDEX', sequelize.col('period'), ">", 1), "%Y-%c-%d"), 'payroll_start'],
          [sequelize.fn('STR_TO_DATE', sequelize.fn('SUBSTRING_INDEX', sequelize.col('period'), ">", -1), "%Y-%c-%d"), 'payroll_end']
        ],
        where: {
          unit_id: unitIds
        },
        having: {
          [Op.and]: [
            {
              payroll_start: {
                [Op.lte]: weekOf
              }
            },
            {
              payroll_end: {
                [Op.gte]: weekOf
              }
            }
          ]
        }
      })
      const payrollByUnit = new Map()
      const payrollPeriods = new Map()
      payrolls.forEach(p => {
        payrollByUnit.set(p.id, p.unit_id)
        if (!payrollPeriods.has(p.period)) {
          payrollPeriods.set(p.period, new Set())
        }
        payrollPeriods.get(p.period).add(p.unit_id)
      })

      const gross_wages = await models.employee_payroll.findAll({
        group: ['payroll_id', 'employee_type'],
        attributes: [
          'payroll_id',
          'employee_type',
          [sequelize.fn('sum', sequelize.col('gross_wages')), 'gross_wages'],
        ],
        where: {
          [Op.and]: [
            {
              payroll_id: payrolls.map(s => s.id)
            }
          ]
        }
      })

      gross_wages.forEach(wages => {
        const unitId = payrollByUnit.get(wages.payroll_id)
        if (wages.employee_type === 'Salary') {
          unitPayroll.get(unitId).salary += wages.gross_wages
        } else if (wages.employee_type === 'Check') {
          unitPayroll.get(unitId).check += wages.gross_wages
        }
      })

      const saleByUnit = new Map()
      for (const period of Array.from(payrollPeriods.keys())) {
        const from = period.split('>')[0]
        const to = period.split('>')[1]
        const periodSales = await models.sale.findAll({
          having: {
            [Op.and]: [
              {
                sales_date: {
                  [Op.gte]: from
                }
              },
              {
                sales_date: {
                  [Op.lte]: to
                }
              },
              {
                unit_id: Array.from(payrollPeriods.get(period).values())
              }
            ]
          },
          raw: true
        })

        periodSales.forEach(s => {
          saleByUnit.set(s.id, s.unit_id)
          unitPayroll.get(s.unit_id).sale_days++
        })

        periodSales.forEach(s => {
          const unitId = saleByUnit.get(s.id)
          unitPayroll.get(unitId).gross_sales += s.gross_sales
          unitPayroll.get(unitId).tax += s.tax
          unitPayroll.get(unitId).net_sales += s.net_sales
          unitPayroll.get(unitId).net_sales_uber_eats += s.net_sales_uber_eats
          unitPayroll.get(unitId).tax_uber_eats += s.tax_uber_eats
          unitPayroll.get(unitId).net_sales_postmates += s.net_sales_postmates
          unitPayroll.get(unitId).tax_postmates += s.tax_postmates
          unitPayroll.get(unitId).credit_sales += s.credit_sales
          unitPayroll.get(unitId).amex_credit_sales += s.amex_credit_sales
          unitPayroll.get(unitId).master_credit_sales += s.master_credit_sales
          unitPayroll.get(unitId).discover_credit_sales += s.discover_credit_sales
          unitPayroll.get(unitId).visa_credit_sales += s.visa_credit_sales
          unitPayroll.get(unitId).debit_sales += s.debit_sales
          unitPayroll.get(unitId).gift_card_redeem += s.gift_card_redeem
          unitPayroll.get(unitId).gift_card_sold += s.gift_card_sold
          unitPayroll.get(unitId).donations += s.donations
          unitPayroll.get(unitId).cash += s.cash
          unitPayroll.get(unitId).rbi_mobile_app += s.rbi_mobile_app
          unitPayroll.get(unitId).uber_eats += s.uber_eats
          unitPayroll.get(unitId).grubhub += s.grubhub
          unitPayroll.get(unitId).doordash += s.doordash
          unitPayroll.get(unitId).white_label += s.white_label
          unitPayroll.get(unitId).postmates += s.postmates
          unitPayroll.get(unitId).snackpass += s.snackpass
          unitPayroll.get(unitId).voids += s.voids
          unitPayroll.get(unitId).voids_amount += s.voids_amount
          unitPayroll.get(unitId).refunds += s.refunds
          unitPayroll.get(unitId).refunds_amount += s.refunds_amount
          unitPayroll.get(unitId).discounts += s.discounts
          unitPayroll.get(unitId).discounts_amount += s.discounts_amount
        })
      }

      const expenses = await models.sales_expense.findAll({
        group: [
          'sale_id',
          'expense_id'
        ],
        attributes: [
          'sale_id',
          'expense_id',
          [sequelize.fn('sum', sequelize.col('amount')), 'amount'],
        ],
        where: {
          [Op.and]: [
            {
              sale_id: [...saleByUnit.keys()]
            }
          ]
        },
        logging: false
      })
      expenses.forEach(s => {
        const unitId = saleByUnit.get(s.sale_id)
        if (s.expense_id === 2) {
          unitPayroll.get(unitId).cash_pay += s.amount
        } else {
          unitPayroll.get(unitId).expenses += s.amount
        }
      })

      const deposits = await models.sales_deposit.findAll({
        group: ['sale_id'],
        attributes: [
          'sale_id',
          [sequelize.fn('SUM', sequelize.col('amount')), 'amount']
        ],
        where: {
          sale_id: [...saleByUnit.keys()]
        },
        logging: false
      })
      deposits.forEach(s => {
        const unitId = saleByUnit.get(s.sale_id)
        unitPayroll.get(unitId).deposits += s.amount
      })

      const deliveries = await models.sales_food_delivery.findAll({
        group: ['sale_id'],
        attributes: [
          'sale_id',
          [sequelize.fn('sum', sequelize.col('amount')), 'amount'],
        ],
        where: {
          [Op.and]: [
            {
              sale_id: [...saleByUnit.keys()]
            }
          ]
        },
        logging: false
      })
      deliveries.forEach(s => {
        const unitId = saleByUnit.get(s.sale_id)
        unitPayroll.get(unitId).deliveries += s.amount
      })

      return [...unitPayroll.values()]
    },
    file_archive_files: (_, { unit_id, date }) => models.file_archive.findAll({
      where: {
        unit_id,
        date
      }
    }),
    async attendance_for_employee(_, { month, year }) {
      try {
        const where = {};

        if (month && year) {
          console.log('Input month:', month, 'Input year:', year);
          if (!/^\d+$/.test(month) || !/^\d+$/.test(year)) {
            throw new Error('Month and year must be numeric strings');
          }
          const monthNum = parseInt(month, 10);
          const yearNum = parseInt(year, 10);
          if (monthNum < 1 || monthNum > 12) {
            throw new Error('Month must be between 1 and 12');
          }
          if (yearNum < 1900 || yearNum > 9999) {
            throw new Error('Year must be a valid four-digit number');
          }
          const startDate = new Date(yearNum, monthNum - 1, 1);
          const endDate = new Date(yearNum, monthNum, 0);
          console.log('Start date:', startDate, 'End date:', endDate);
          if (isNaN(startDate.getTime()) || isNaN(endDate.getTime())) {
            throw new Error('Invalid date range calculated');
          }
          where.date = {
            [Op.between]: [startDate, endDate],
          };
        }

        console.log('Where clause:', where);
        const attendances = await models.attendance.findAll({
          where,
          order: [['date', 'ASC']],
        });

        console.log('Fetched attendances:', attendances);
        return attendances.map(att => {
          // Convert date and created_at to Date objects or null
          const date = att.date ? new Date(att.date) : null;
          const created_at = att.created_at ? new Date(att.created_at) : null;

          return {
            id: att.id,
            dummyemployees: att.dummyemployees,
            department: att.department,
            location: att.location,
            markBy: att.markBy,
            year: att.year,
            month: att.month,
            date: date && !isNaN(date.getTime()) ? date : null,
            clockIn: att.clockIn,
            clockOut: att.clockOut,
            other: att.other,
            late: att.late,
            halfDay: att.halfDay,
            workingFrom: att.workingFrom,
            overwrite: att.overwrite,
            created_at: created_at && !isNaN(created_at.getTime()) ? created_at : null,
          };
        });
      } catch (error) {
        console.error('Error fetching attendance:', error.message, error.stack);
        throw new Error(`Failed to fetch attendance records: ${error.message}`);
      }
    },
    // get_properties: async (_) => {
    //   const properties = await models.property.findAll({
    //     order: [['name', 'ASC']],
    //     include: [
    //       {
    //         model: models.owner,
    //         as: 'owners',
    //         through: { attributes: [] },
    //       },
    //     ],
    //   });

    //   // Ensure owners is always an array
    //   return properties.map((p) => {
    //     if (p.owners === null) {
    //       p.owners = [];
    //     }
    //     return p;
    //   });
    // },

    get_properties: async (_, { unit_id }, context) => {
      console.log('Received query with unit_id:', unit_id);
      return await models.property.findAll({
        order: [['id', 'ASC']],
        where: { unit_id },
      });
    },

    get_tenants: async (_, { unit_id }) => {
      return await models.tenants.findAll({
        where: { unit_id },
        order: [['id', 'ASC']]
      });
    },

    get_payment_transaction: async (_, { unit_id }) => {
      console.log('get payment transaction unit id ', unit_id);

      const transactions = await models.revenue_received.findAll({
        where: {
          unit_id,
          type: 'tenant',
        },
        order: [['createdAt', 'DESC']],
        include: [
          {
            model: models.tenant_revenue_received,
            as: 'tenant_revenues',
            include: [
              {
                model: models.tenants,
                as: 'tenant',
                attributes: [
                  'id',
                  'indi_corp_type',
                  'first_name',
                  'last_name',
                  'ssn',
                  'corporation_name',
                ],
              },
            ],
          },
        ],
      });

      return transactions.map(txn => ({
        id: txn.id,
        tenant_id: txn.tenant_revenues?.[0]?.tenant_id || null,
        invoice_ids: txn.invoice_ids || [],
        amount: parseFloat(txn.amount),
        payment_mode: txn.payment_mode,
        payment_date: txn.createdAt?.toISOString() || '',
        send_email: false,
        print_receipt: false,
        check_details:
          txn.cheque_number || txn.routing_number || txn.cheque_due_date
            ? {
              number: txn.cheque_number || '',
              account: txn.account_number || '',
              routing: txn.routing_number || '',
              date: txn.cheque_due_date?.toISOString() || '',
            }
            : null,
        card_number: txn.card_number || '',
        barter_description: txn.barter_description || '',
        zelle_description: txn.zelle_description || '',
        PaymentTenant: txn.tenant_revenues?.map(tr => tr.tenant) || [],
      }));
    },

    get_client_payment_transaction: async (_, { unit_id }) => {
      console.log('get payment transaction unit id ', unit_id);

      const transactions = await models.revenue_received.findAll({
        where: {
          unit_id,
          type: 'client',
        },
        order: [['createdAt', 'DESC']],
        include: [
          {
            model: models.client_revenue_received,
            as: 'client_revenues',
            include: [
              {
                model: models.client,
                as: 'client',
                attributes: [
                  'id',
                  'first_name',
                  'last_name',
                ],
              },
            ],
          },
        ],
      });

      return transactions.map(txn => ({
        id: txn.id,
        client_id: txn.client_revenues?.[0]?.client_id || null,
        invoice_ids: txn.invoice_ids || [],
        amount: parseFloat(txn.amount),
        payment_mode: txn.payment_mode,
        payment_date: txn.createdAt?.toISOString() || '',
        send_email: false,
        print_receipt: false,
        check_details:
          txn.cheque_number || txn.routing_number || txn.cheque_due_date
            ? {
              number: txn.cheque_number || '',
              account: txn.account_number || '',
              routing: txn.routing_number || '',
              date: txn.cheque_due_date?.toISOString() || '',
            }
            : null,
        card_number: txn.card_number || '',
        barter_description: txn.barter_description || '',
        zelle_description: txn.zelle_description || '',
        PaymentClient: txn.client_revenues?.map(tr => tr.client) || [],
      }));
    },

    get_invoices: async (_, { unit_id, type }) => {
      try {
        if (!unit_id || !['tenant', 'client'].includes(type)) {
          throw new Error('Invalid unit_id or type. Type must be "tenant" or "client".');
        }

        const includeModels = [
          {
            model: models.invoice_items,
            as: 'items',
          },
        ];

        if (type === 'tenant') {
          console.log("tennat here hit")
          includeModels.push({
            model: models.tenant_invoices,
            as: 'tenant_invoices',
            include: [
              {
                model: models.tenants,
                as: 'tenant',
                attributes: ['id', 'indi_corp_type', 'first_name', 'last_name', 'corporation_name'],
              },
            ],
          });
        } else if (type === 'client') {
          includeModels.push({
            model: models.client_invoices,
            as: 'client_invoices',
            include: [
              {
                model: models.client,
                as: 'client',
                attributes: ['id', 'first_name', 'last_name', 'ssn'],
              },
            ],
          });
        }

        const invoices = await models.invoices.findAll({
          where: {
            unit_id: unit_id,
            type: type,
          },
          order: [['id', 'ASC']],
          include: includeModels,
        });

        const finalRecord = invoices.map(inv => {
          const invoice = inv.toJSON();
          invoice.items = invoice.items.map(item => ({
            ...item,
            name: item.title || 'Untitled',
          }));

          if (type === 'tenant' && invoice.tenant_invoices?.length > 0) {
            invoice.entity = { ...invoice.tenant_invoices[0].tenant, __typename: 'TenantForInvoice' };
            invoice.tenant_id = invoice.tenant_invoices[0].tenant.id;  // Set from associated tenant.id
            delete invoice.tenant_invoices;
          } else if (type === 'client' && invoice.client_invoices?.length > 0) {
            invoice.entity = { ...invoice.client_invoices[0].client, __typename: 'ClientForInvoice' };
            invoice.client_id = invoice.client_invoices[0].client.id;  // Set from associated client.id
            delete invoice.client_invoices;
          }

          return invoice;
        });

        return finalRecord;
      } catch (error) {
        console.error('Error fetching invoices:', error);
        throw new Error('Failed to fetch invoices. Please try again later.');
      }
    },

    get_invoice_number: async (_, { unit_id }) => {
      try {
        if (!unit_id) {
          throw new Error('Invalid unit_id.');
        }

        const invoices = await models.invoices.findAll({
          where: { unit_id: unit_id, },
          attributes: ['invoice_no'],
          order: [['id', 'ASC']],
        });

        console.log('get invoice number', invoices);


        return invoices.map(invoice => ({
          invoice_number: invoice.invoice_no,
        }));
      } catch (error) {
        console.error('Error fetching invoice numbers:', error);
        throw new Error('Failed to fetch invoice numbers. Please try again later.');
      }
    },

    get_tenant_balance_by_id: async (_, { tenant_id }) => {
      const { opening_balance } = await models.tenants.findByPk(tenant_id, {
        attributes: ['opening_balance']
      });
      return { opening_balance };
    },

    get_client_balance_by_id: async (_, { client_id }) => {
      const { opening_balance } = await models.client.findByPk(client_id, {
        attributes: ['opening_balance']
      });
      return { opening_balance };
    },

    async get_recurring_invoices(_, { unit_id, type }) {
      try {
        if (!unit_id || !['tenant', 'client'].includes(type)) {
          throw new Error('Invalid unit_id or type. Type must be "tenant" or "client".');
        }

        const includeModels = [
          {
            model: models.recurring_invoice_items,
            as: 'items',
          },
        ];

        if (type === 'tenant') {
          console.log("tenant recurring invoices hit");
          includeModels.push({
            model: models.tenant_recurring_invoices,
            as: 'tenant_recurring_invoices',
            include: [
              {
                model: models.tenants,
                as: 'tenant',
                attributes: ['id', 'indi_corp_type', 'first_name', 'last_name', 'corporation_name'],
              },
            ],
          });
        } else if (type === 'client') {
          includeModels.push({
            model: models.client_recurring_invoices,
            as: 'client_recurring_invoices',
            include: [
              {
                model: models.client,
                as: 'client',
                attributes: ['id', 'first_name', 'last_name', 'ssn'],
              },
            ],
          });
        }

        const recurring_invoices = await models.recurring_invoices.findAll({
          where: {
            unit_id: unit_id,
            type: type,
          },
          order: [['id', 'ASC']],
          include: includeModels,
        });

        const finalRecord = recurring_invoices.map(inv => {
          const invoice = inv.toJSON();
          invoice.items = invoice.items.map(item => ({
            ...item,
            name: item.title || 'Untitled',
          }));

          if (type === 'tenant' && invoice.tenant_recurring_invoices?.length > 0) {
            invoice.entity = { ...invoice.tenant_recurring_invoices[0].tenant, __typename: 'TenantForRecurringInvoice' };
            invoice.tenant_id = invoice.tenant_recurring_invoices[0].tenant.id;
            delete invoice.tenant_recurring_invoices;
          } else if (type === 'client' && invoice.client_recurring_invoices?.length > 0) {
            invoice.entity = { ...invoice.client_recurring_invoices[0].client, __typename: 'ClientForRecurringInvoice' };
            invoice.client_id = invoice.client_recurring_invoices[0].client.id;
            delete invoice.client_recurring_invoices;
          }

          return invoice;
        });

        return finalRecord;
      } catch (error) {
        console.error('Error fetching recurring invoices:', error);
        throw new Error(`Failed to fetch recurring invoices: ${error.message}`);
      }
    },

    get_memorized_invoices: async (_, { unit_id, type }) => {
      try {
        // Fetch memorized invoices based on unit_id
        const memorized = await models.memorized_invoice.findAll({
          where: { unit_id },
          include: [
            {
              model: models.recurring_invoices,
              as: 'recurring_invoice',
              include: [
                {
                  model: models.recurring_invoice_items,
                  as: 'items',
                  required: false, // Include items even if none exist
                  attributes: ['id', 'title', 'amount', 'code'],
                },
                {
                  model: models.tenant_recurring_invoices,
                  as: 'tenant_recurring_invoices',
                  required: type === 'tenant', // Only require for tenant type
                  include: [
                    {
                      model: models.tenants,
                      as: 'tenant',
                      attributes: [
                        'id',
                        'indi_corp_type',
                        'first_name',
                        'last_name',
                        'corporation_name',
                        'street_number',
                        'phone',
                        'email',
                      ],
                    },
                  ],
                },
                {
                  model: models.client_recurring_invoices,
                  as: 'client_recurring_invoices',
                  required: type === 'client', // Only require for client type
                  include: [
                    {
                      model: models.client,
                      as: 'client',
                      attributes: ['id', 'first_name', 'last_name', 'ssn', 'phone', 'email'],
                    },
                  ],
                },
              ],
              attributes: [
                'id',
                'issue_date',
                'frequency',
                'next_date',
                'due_date',
                'note',
                'subtotal',
                'discount',
                'discount_type',
                'total',
              ],
            },
          ],
        });

        // Map Sequelize results to GraphQL schema
        return memorized.map((m) => {
          const invoice = m.recurring_invoice;
          return {
            id: m.id,
            invoice_pay_month: m.invoice_pay_month || (invoice?.next_date ? invoice.next_date.toISOString().slice(0, 7) : null), // Format as YYYY-MM
            status: m.status || (invoice?.next_date !== null), // Use memorized status or derive from next_date
            recurring_invoice: invoice
              ? {
                issue_date: invoice.issue_date.toISOString(),
                frequency: invoice.frequency,
                next_date: invoice.next_date ? invoice.next_date.toISOString() : null,
                due_date: invoice.due_date.toISOString(),
                note: invoice.note,
                subtotal: invoice.subtotal,
                discount: invoice.discount,
                discount_type: invoice.discount_type,
                total: invoice.total,
                entity: (() => {
                  if (type === 'tenant' && invoice.tenant_recurring_invoices?.length > 0) {
                    const tenant = invoice.tenant_recurring_invoices[0].tenant;
                    return {
                      __typename: 'TenantForMemorizedInvoice',
                      id: tenant.id,
                      indi_corp_type: tenant.indi_corp_type || null,
                      first_name: tenant.first_name || null,
                      last_name: tenant.last_name || null,
                      corporation_name: tenant.corporation_name || null,
                      street_number: tenant.street_number || null,
                      phone: tenant.phone || null,
                      email: tenant.email || null,
                    };
                  } else if (type === 'client' && invoice.client_recurring_invoices?.length > 0) {
                    const client = invoice.client_recurring_invoices[0].client;
                    return {
                      __typename: 'ClientForMemorizedInvoice',
                      id: client.id,
                      first_name: client.first_name || null,
                      last_name: client.last_name || null,
                      ssn: client.ssn || null,
                      phone: client.phone || null,
                      email: client.email || null,
                    };
                  }
                  return null;
                })(),
                items: invoice.items.map((item) => ({
                  id: item.id,
                  title: item.title,
                  amount: item.amount,
                  code: item.code || null,
                })),
              }
              : null,
          };
        });
      } catch (error) {
        console.error('Error fetching memorized invoices:', error);
        throw new Error(`Failed to fetch memorized invoices: ${error.message}`);
      }
    },

    get_client_memorized_invoices: async (_, { unit_id, type }) => {
      try {
        if (!unit_id) {
          throw new Error('Invalid unit_id.');
        }

        const recurringInvoiceIncludes = [
          {
            model: models.recurring_invoice_items,
            as: 'items',
            required: false,
            attributes: ['id', 'title', 'amount', 'code'],
          },
          {
            model: models.client_recurring_invoices,
            as: 'client_recurring_invoices',
            required: false,
            include: [
              {
                model: models.client,
                as: 'client',
                attributes: ['id', 'first_name', 'last_name', 'ssn', 'phone', 'email'],
              },
            ],
          },
        ];

        const memorized = await models.memorized_invoice.findAll({
          where: { unit_id },
          include: [
            {
              model: models.recurring_invoices,
              as: 'recurring_invoice',
              include: recurringInvoiceIncludes,
              attributes: [
                'id',
                'issue_date',
                'frequency',
                'next_date',
                'due_date',
                'note',
                'subtotal',
                'discount',
                'discount_type',
                'total',
              ],
            },
          ],
        });

        return memorized.map((m) => {
          const invoice = m.recurring_invoice;
          if (!invoice || !invoice.client_recurring_invoices?.length) return null;

          const client = invoice.client_recurring_invoices[0].client;
          const entity = {
            __typename: 'ClientForMemorizedInvoice',
            id: client.id,
            first_name: client.first_name || null,
            last_name: client.last_name || null,
            ssn: client.ssn || null,
            phone: client.phone || null,
            email: client.email || null,
          };

          return {
            id: m.id,
            invoice_pay_month: m.invoice_pay_month || (invoice.next_date ? invoice.next_date.toISOString().slice(0, 7) : null),
            status: m.status || (invoice.next_date !== null),
            recurring_invoice: invoice ? {
              issue_date: invoice.issue_date.toISOString(),
              frequency: invoice.frequency,
              next_date: invoice.next_date ? invoice.next_date.toISOString() : null,
              due_date: invoice.due_date.toISOString(),
              note: invoice.note,
              subtotal: invoice.subtotal,
              discount: invoice.discount,
              discount_type: invoice.discount_type,
              total: invoice.total,
              entity: entity,
              items: invoice.items ? invoice.items.map((item) => ({
                id: item.id,
                title: item.title,
                amount: item.amount,
                code: item.code || null,
              })) : [],
            } : null,
          };
        }).filter(Boolean);
      } catch (error) {
        console.error('Error fetching memorized invoices:', error);
        throw new Error(`Failed to fetch memorized invoices: ${error.message}`);
      }
    },

    // get_memorized_invoices: async (_, { unit_id, type }) => {
    //   try {
    //     // Fetch recurring invoices based on unit_id and type
    //     const where = { unit_id, type };
    //     const recurringInvoices = await models.recurring_invoices.findAll({
    //       where,
    //       include: [
    //         {
    //           model: models.recurring_invoice_items,
    //           as: 'items',
    //           required: false, // Include items even if none exist
    //         },
    //         {
    //           model: models.tenant_recurring_invoices,
    //           as: 'tenant_recurring_invoices',
    //           required: type === 'tenant', // Only require for tenant type
    //           include: [
    //             {
    //               model: models.tenants,
    //               as: 'tenant',
    //             },
    //           ],
    //         },
    //         {
    //           model: models.client_recurring_invoices,
    //           as: 'client_recurring_invoices',
    //           required: type === 'client', // Only require for client type
    //           include: [
    //             {
    //               model: models.client,
    //               as: 'client',
    //             },
    //           ],
    //         },
    //       ],
    //     });

    //     // Map Sequelize results to GraphQL schema
    //     return recurringInvoices.map((invoice) => ({
    //       id: invoice.id,
    //       invoice_pay_month: invoice.next_date ? invoice.next_date.toISOString().slice(0, 7) : null, // Format as YYYY-MM
    //       status: invoice.next_date !== null, // Example logic: active if next_date exists
    //       recurring_invoice: {
    //         issue_date: invoice.issue_date.toISOString(),
    //         frequency: invoice.frequency,
    //         next_date: invoice.next_date ? invoice.next_date.toISOString() : null,
    //         due_date: invoice.due_date.toISOString(),
    //         note: invoice.note,
    //         subtotal: invoice.subtotal,
    //         discount: invoice.discount,
    //         discount_type: invoice.discount_type,
    //         total: invoice.total,
    //         entity: (() => {
    //           if (type === 'tenant' && invoice.tenant_recurring_invoices.length > 0) {
    //             const tenant = invoice.tenant_recurring_invoices[0].tenant;
    //             return {
    //               __typename: 'TenantForMemorizedInvoice',
    //               id: tenant.id,
    //               indi_corp_type: tenant.indi_corp_type || null,
    //               first_name: tenant.first_name || null,
    //               last_name: tenant.last_name || null,
    //               corporation_name: tenant.corporation_name || null,
    //               street_number: tenant.street_number || null,
    //               phone: tenant.phone || null,
    //               email: tenant.email || null,
    //             };
    //           } else if (type === 'client' && invoice.client_recurring_invoices.length > 0) {
    //             const client = invoice.client_recurring_invoices[0].client;
    //             return {
    //               __typename: 'ClientForMemorizedInvoice',
    //               id: client.id,
    //               first_name: client.first_name || null,
    //               last_name: client.last_name || null,
    //               ssn: client.ssn || null,
    //               phone: client.phone || null,
    //               email: client.email || null,
    //             };
    //           }
    //           return null;
    //         })(),
    //         items: invoice.items.map((item) => ({
    //           id: item.id,
    //           title: item.title,
    //           amount: item.amount,
    //           code: item.code || null,
    //         })),
    //       },
    //     }));
    //   } catch (error) {
    //     console.error('Error fetching memorized invoices:', error);
    //     throw new Error(`Failed to fetch memorized invoices: ${error.message}`);
    //   }
    // },

    get_property_owner: async (_) => {
      return await models.owner.findAll({
        order: [['id', 'ASC']]
      });
    },
    get_leave_type: async (_) => {
      return await models.leave_types.findAll({
        order: [['id', 'ASC']]
      });
    },

    get_leaves: async (_, { unit_id }) => {

      try {
        if (unit_id === undefined || unit_id === null || isNaN(unit_id)) {
          console.warn(`⚠️ Invalid unit_id provided: ${unit_id}`)
          return []
        }

        const data = await models.leave.findAll({
          where: { unit_id },
          order: [['id', 'ASC']],
          include: [
            {
              model: models.employee,
              as: 'employee',
              attributes: ['id', 'firstname', 'lastname'],
            },
            {
              model: models.leave_types,
              as: 'leaveType',
              attributes: ['id', 'type_name', 'no_of_leaves'],
            },
          ],
        })

        console.log(`✅ Fetched ${data.length} leaves for unit_id ${unit_id}`)
        return data
      } catch (err) {
        console.error('💥 Error fetching leaves:', err)
        return []
      }
    },

    get_leaves_by_employee: async (_, { employee_id }) => {
      console.log('📄 get_leaves_by_employee called for employee_id:', employee_id);

      try {
        if (employee_id === undefined || employee_id === null || isNaN(employee_id)) {
          console.warn(`⚠️ Invalid employee_id provided: ${employee_id}`);
          return [];
        }

        const data = await models.leave.findAll({
          where: { employee_id },
          order: [['id', 'ASC']],
          include: [
            {
              model: models.employee,
              as: 'employee',
              attributes: ['id', 'firstname', 'lastname', 'social_security_num'],
            },
            {
              model: models.leave_types,
              as: 'leaveType',
              attributes: ['id', 'type_name', 'no_of_leaves'],
            },
          ],
        });

        const transformedData = data.map(leave => {
          const jsonLeave = leave.toJSON();

          // 🔧 Fix: Ensure date_range is always an array
          let normalizedDateRange = [];
          if (jsonLeave.date_range) {
            try {
              // if it's a JSON string, parse it
              const parsed = JSON.parse(jsonLeave.date_range);
              normalizedDateRange = Array.isArray(parsed) ? parsed : [parsed];
            } catch {
              // if it's not valid JSON, just wrap in array
              normalizedDateRange = [jsonLeave.date_range];
            }
          }

          return {
            ...jsonLeave,
            leave_type: jsonLeave.leave_type || jsonLeave.leaveType?.type_name || 'ANNUAL',
            date_range: normalizedDateRange,
          };
        });

        console.log('✅ Transformed leaves data:', transformedData);
        return transformedData;
      } catch (err) {
        console.error('❌ Error fetching leaves:', err);
        return [];
      }
    },

    get_leaves_by_employee_app: async (_, { employee_id }) => {
      console.log('get_leaves_by_employee_app called for employee_id:', employee_id);

      try {
        if (!employee_id || isNaN(employee_id)) {
          console.warn(`Invalid employee_id provided: ${employee_id}`);
          return [];
        }

        const leaves = await models.leave.findAll({
          where: { employee_id },
          order: [['id', 'ASC']],
          attributes: [
            'id',
            'employee_id',
            'status',
            'duration',
            'date',
            'date_range',
            'reason',
            'created_at',
            'created_by',
          ],
          include: [
            {
              model: models.employee,
              as: 'employee',
              attributes: ['id', 'firstname', 'lastname', 'social_security_num'],
              required: true,
            },
          ],
        });

        const transformedData = leaves.map(leave => {
          const jsonLeave = leave.toJSON();

          // Normalize date_range to always be [String]
          let date_range = [];
          if (jsonLeave.date_range) {
            try {
              const parsed = JSON.parse(jsonLeave.date_range);
              date_range = Array.isArray(parsed)
                ? parsed.filter(d => typeof d === 'string')
                : typeof parsed === 'string'
                  ? [parsed]
                  : [];
            } catch {
              if (typeof jsonLeave.date_range === 'string') {
                date_range = [jsonLeave.date_range];
              }
            }
          }

          // Format created_at as ISO string
          const created_at = jsonLeave.created_at
            ? new Date(jsonLeave.created_at).toISOString()
            : new Date().toISOString();

          return {
            id: jsonLeave.id,
            employee_id: jsonLeave.employee_id,
            employee: {
              id: jsonLeave.employee.id,
              firstname: jsonLeave.employee.firstname,
              lastname: jsonLeave.employee.lastname,
              social_security_num: jsonLeave.employee.social_security_num,
            },
            status: jsonLeave.status || 'PENDING',
            duration: jsonLeave.duration || 'FULL_DAY',
            date: jsonLeave.date || null,
            date_range,
            reason: jsonLeave.reason || '',
            created_at,
          };
        });

        console.log('Transformed leaves:', transformedData.length, 'records');
        return transformedData;
      } catch (err) {
        console.error('Error in get_leaves_by_employee_app:', err);
        return [];
      }
    },

    get_designations: async (_) => {
      return await models.job_title.findAll({
        order: [['id', 'ASC']]
      });
    },

    get_departments: async (_parent, { unit_id }) => {
      try {
        if (!unit_id || isNaN(unit_id)) {
          console.warn(`Invalid unit_id provided: ${unit_id}`);
          return [];
        }
        console.log("unit_id in departments:", unit_id);
        const departments = await models.department.findAll({
          where: { unit_id },
          order: [['id', 'ASC']],
        });

        if (!departments || departments.length === 0) {
          console.warn(`No departments found for unit_id ${unit_id}`);
          return [];
        }

        return departments;
      } catch (err) {
        console.error('Error fetching departments:', err);
        throw new Error('Failed to fetch departments');
      }
    },

    // get_holidays: async (_) => {
    //   return await models.holiday.findAll({
    //     order: [['id', 'ASC']]
    //   });
    // },

    get_holidays: async (_parent, { unit_id }) => {
      console.log('Fetching holidays for unit_id:', unit_id)

      try {
        if (unit_id === undefined || unit_id === null || isNaN(unit_id)) {
          console.warn(`Invalid unit_id provided: ${unit_id}`)
          return []
        }

        const holidays = await models.holiday.findAll({
          where: { unit_id },
          order: [['id', 'ASC']],
        })

        return holidays.map(h => {
          const holiday = h.toJSON()

          holiday.department = holiday.department
            ? JSON.parse(holiday.department).filter(Boolean)
            : []

          holiday.designation = holiday.designation
            ? JSON.parse(holiday.designation).filter(Boolean)
            : []

          holiday.employee_type = holiday.employee_type
            ? JSON.parse(holiday.employee_type).filter(Boolean)
            : []

          return holiday
        })
      } catch (err) {
        console.error('Error fetching holidays:', err)
        return []
      }
    },


    get_chart_account_type: async () => {
      const data = await models.chart_account_type.findAll();
      console.log("data charts type", data)
      return data;
    },

    get_chart_accounts: async (_, { unit_id }) => {
      try {
        const data = await models.chart_of_account.findAll({
          where: { unit_id },
        });

        console.log("data charts by unit_id:", data);

        return data.map(acc => acc.get({ plain: true }));
      } catch (err) {
        console.error("Error fetching chart accounts:", err);
        throw new Error("Failed to fetch chart accounts");
      }
    },


    get_checks: async (_, { unit_id }) => {
      try {
        const data = await models.checks.findAll({
          where: { unit_id },
          include: [
            {
              model: models.check_items,
              as: 'items'
            },
            {
              model: models.vendor,
              as: 'vendor',
              attributes: ['id', 'vendor_name', 'email', 'billed_street', 'billed_suite', 'billed_zip', 'billed_city', 'billed_state']
            },
            {
              model: models.NewBank,
              as: 'bank',
              attributes: ['id', 'name', 'account_name', 'account_no', 'routing_no', 'street_no', 'city', 'state', 'zip_code',]
            }
          ],
          order: [['id', 'DESC']]
        });

        return data;
      } catch (error) {
        console.error('Error fetching checks:', error.message);
        throw new Error(error.message);
      }
    },

    // get_invitations: async () => {
    //   const data = await models.invitation.findAll();
    //   console.log("data invitation ", data)
    //   return data;
    // },

    get_invitations: async (_, { unit_id }) => {

      console.log('get invitations', unit_id);

      try {
        if (unit_id === undefined || unit_id === null || isNaN(unit_id)) {
          console.warn(`Invalid unit_id provided: ${unit_id}`)
          return []
        }

        const data = await models.invitation.findAll({
          where: { unit_id },
          order: [['id', 'ASC']],
        });

        console.log(`Fetched invitations for unit_id ${unit_id}:`, data)
        return data
      } catch (err) {
        console.error('Error fetching invitations:', err)
        return []
      }
    },



    get_expense_type: async () => {
      const data = await models.ExpenseType.findAll();
      console.log("data Expense Type ", data)
      return data;
    },

    get_expenses: async () => {
      const data = await models.expenses.findAll({
        include: [
          {
            model: models.ExpenseType,
            as: 'expenseType',
            attributes: ['id', 'type_name', 'type_date'],
          },
        ],
      });

      return data.map(exp => ({
        ...exp.get({ plain: true }),
        expense_type: exp.expenseType ? [exp.expenseType] : []
      }));
    },

    get_consents: async (_, { unit_id }) => {
      try {
        const data = await models.signConsentDocs.findAll({
          where: { unit_id },
        });
        // Transform data to match GraphQL schema
        const transformedData = data.map(item => ({
          id: item.id,
          document_title: item.document_title,
          document_type: item.document_type,
          uploaded_document: item.uploaded_document,
          mustBeSigned: item.must_be_signed ? 'true' : 'false',
          notes: item.notes,
          unit_id: item.unit_id,
        }));
        console.log("data consents for unitId", unit_id, transformedData);
        return transformedData;
      } catch (error) {
        console.error("Error fetching consents for unitId", unit_id, error);
        throw new Error("Failed to fetch consents");
      }
    },

    attendanceLogs_by_id: async (_, { employee_id }) => {
      const data = await models.employee_attendance.findAll({
        attributes: [
          "id",
          "employee_id",
          "date",
          "clock_in_time",
          "clock_out_time",
          "status",
          "location",
          "late",
          "half_day",

        ],
        where: {
          employee_id: employee_id
        },
        order: [["date", "DESC"], ["clock_in_time", "ASC"]]
      });

      console.log("Fetched attendance logs for employee ID:", data);
      return data;
    },

    getUserActivities: async (_, { user_id }) => {
      console.log("Resolver hit for user_id:", user_id);

      try {
        const activities = await models.user_activity.findAll({
          where: { user_id: user_id },
          order: [["id", "DESC"]],
          include: [
            {
              model: models.user,
              as: "user",
              attributes: ["id", "name", "email"],
            },
          ],
        });

        return activities.map((a) => ({
          id: a.id,
          activity_type: a.activity_type,
          activity_time: a.activity_time,
          details: a.details,
          status: a.status,
          ip_address: a.ip_address,
          user_agent: a.user_agent,
          user: a.user
            ? {
              user_id: a.user.id,
              name: a.user.name,
              email: a.user.email,
            }
            : null,
        }));
      } catch (error) {
        console.error("Error fetching user activities:", error);
        return [];
      }
    },

    get_signDocs: async (_, { employee_id }) => {
      console.log("Resolver hit for employee_id:", employee_id);
      try {
        const signConsentDocs = await models.signConsentDocs.findAll();
        console.log("signConsentDocs:", signConsentDocs);

        if (!signConsentDocs || signConsentDocs.length === 0) {
          console.log("No consent documents found for employee:", employee_id);
          return [];
        }

        const results = [];

        for (const doc of signConsentDocs) {
          // Check if the document is accepted by the employee
          const isAccepted = await models.signconsent_employee.findOne({
            where: {
              sign_consent_id: doc.id,
              employee_id: employee_id,
            },
          });

          const data = {
            id: doc.id,
            document_title: doc.document_title,
            document_type: doc.document_type,
            upload_docs: doc.uploaded_document,
            must_be_signed: !!doc.must_be_signed,
            notes: doc.notes,
            path: null,
            status: !!isAccepted, // Convert to boolean
          };


          if (doc.uploaded_document) {
            const fileEntry = await models.file_archive.findByPk(doc.uploaded_document);
            if (fileEntry) {
              const params = {
                Bucket: env === 'production' ? 'dream.big.holdings' : 'dream.big.holdings.staging',
                Key: `${fileEntry.path}/${fileEntry.filename}`,
              };
              console.log("S3 params:", params);

              try {
                const s3Response = await s3.getObject(params).promise();
                const fileBuffer = s3Response.Body;
                const base64File = fileBuffer.toString('base64');
                const mimeType = s3Response.ContentType || 'application/pdf';
                data.path = `data:${mimeType};base64,${base64File}`;
                console.log(`File fetched for doc ${doc.id}`);
              } catch (err) {
                console.error(`Error fetching file from S3 for doc ${doc.id}:`, err);
                data.path = null;
              }
            } else {
              console.log("No file_archive entry found for ID:", doc.uploaded_document);
            }
          }
          results.push(data);
        }

        console.log("Returning documents:", results);
        return results;
      } catch (error) {
        console.error("Error fetching sign consent documents:", error);
        throw new Error("Failed to fetch sign consent documents");
      }
    },

    todayAttendance: async (_, { employee_id }) => {
      console.log("Resolver hit for employee_id:", employee_id);

      // Get current date in Pakistan timezone (UTC+5)
      const now = new Date();
      const pakistanOffset = 5 * 60; // +5 hours in minutes
      const localTime = new Date(now.getTime() + pakistanOffset * 60 * 1000);

      // Format YYYY-MM-DD
      const today = localTime.toISOString().slice(0, 10);
      console.log("Today's date in Pakistan time:", today);

      try {
        // Fetch the first attendance record for this employee today
        const record = await models.employee_attendance.findOne({
          attributes: [
            "id",
            "employee_id",
            "date",
            "clock_in_time",
            "clock_out_time",
            "status",
            "location",
          ],
          where: {
            employee_id,
            date: today, // filter strictly for today's date in Pakistan time
          },
          order: [["clock_in_time", "ASC"]], // first clock-in
        });

        console.log("Fetched record for today:", record);

        // Return the record or default object if none exists
        return record || {
          id: null,
          employee_id,
          date: today,
          clock_in_time: null,
          clock_out_time: null,
          status: "absent",
          location: "",
        };
      } catch (error) {
        console.error("Error fetching attendance:", error);
        // Return default object on error
        return {
          id: null,
          employee_id,
          date: today,
          clock_in_time: null,
          clock_out_time: null,
          status: "absent",
          location: "",
        };
      }
    },

    getEmployeeByIDForApp: async (_, { employee_id }) => {
      const data = await models.employee.findOne({
        attributes: [
          "id",
          "firstname",
          "middlename",
          "lastname",
          "address",
          "city",
          "state",
          "zip",
          "country",
          "phone",
          "emergency_phone_number",
          "gender",
          "social_security_num",
          "id_type",
          "id_number",
          "status"
        ],
        where: {
          id: employee_id
        }
      });
      console.log("Fetched employee:", data);
      return data;
    },

    get_property_by_id: async (_, { property_id }) => {
      const property = await models.property.findByPk(property_id, {
        include: [{ model: models.owner, as: 'owners' }],
      });

      if (!property) return null;

      // Map owners -> property_owners for GraphQL
      return {
        ...property.toJSON(),
        property_owners: property.owners || [],
      };
    },

    get_client_by_id: async (_, { client_id }) => {
      const client = await models.client.findByPk(client_id);
      if (!client) {
        console.warn('No client found with ID:', client_id);
        return null;
      }
      return client;
    },

    get_payment_by_id: async (_, { id }) => {
      console.log('Fetching payment id:', id);

      const payment = await models.revenue_received.findByPk(id, {
        include: [
          {
            model: models.tenant_revenue_received,
            as: 'tenant_revenues',
            include: [
              {
                model: models.tenants,
                as: 'tenant',
                attributes: [
                  'id',
                  'indi_corp_type',
                  'first_name',
                  'last_name',
                  'corporation_name',
                ],
              },
            ],
          },
          {
            model: models.client_revenue_received,
            as: 'client_revenues',
            include: [
              {
                model: models.client,
                as: 'client',
                attributes: ['id', 'first_name', 'last_name'],
              },
            ],
          },
        ],
      });

      if (!payment) {
        console.warn('No payment found with ID:', id);
        return null;
      }

      const txn = payment.toJSON();
      const firstTenant = txn.tenant_revenues?.[0]?.tenant || null;
      const firstClient = txn.client_revenues?.[0]?.client || null;

      const response = {
        id: txn.id,
        tenant_id: txn.tenant_revenues?.[0]?.tenant_id || null,
        client_id: txn.client_revenues?.[0]?.client_id || null,
        amount: parseFloat(txn.amount),
        payment_mode: txn.payment_mode,
        send_email: false,
        print_receipt: false,
        createdAt: txn.createdAt || null,
        check_details:
          txn.cheque_number || txn.routing_number || txn.cheque_due_date
            ? {
              check_number: txn.cheque_number || '',
              routing_number: txn.routing_number || '',
              account_number: txn.account_number || '',
              check_due_date: txn.cheque_due_date || '',
              check_status: txn.cheque_status || '',
            }
            : null,
        card_number: txn.card_number || '',
        barter_description: txn.barter_description || '',
        zelle_description: txn.zelle_description || '',
        tenant: firstTenant
          ? {
            id: firstTenant.id,
            indi_corp_type: firstTenant.indi_corp_type,
            first_name: firstTenant.first_name,
            last_name: firstTenant.last_name,
            corporation_name: firstTenant.corporation_name,
          }
          : null,
        PaymentClient: (txn.client_revenues || [])
          .map(cr => cr.client)
          .filter(c => c),
        invoices: [],
      };

      console.log('✅ Final payment response:', response);
      return response;
    },




    fetch_roster_by_id: async (_, { roster_id }) => {
      console.log("wow id here", roster_id);
      const roster = await models.shift_roster.findByPk(roster_id, {
        include: [
          {
            model: models.employee,
            as: 'employee',
            attributes: ['id', 'firstname', 'lastname', 'social_security_num']
          },
          {
            model: models.employee_shift,
            as: 'employee_shift',
            attributes: ['id', 'shift_name', 'shift_type', 'color', 'office_start_time', 'office_end_time', 'flexible_total_hours', 'flexible_half_day_hours']
          }
        ]
      });

      if (!roster) return null;

      // Wrap in array if exists
      return {
        ...roster.toJSON(),
        employee: roster.employee ? [roster.employee] : [],
        employee_shift: roster.employee_shift ? [roster.employee_shift] : []
      };
    },
    get_tenant_by_id: async (_, { tenant_id }) => {
      const tenant = await models.tenants.findByPk(tenant_id)
      if (!tenant) {
        console.warn('No tenant found with ID:', tenant_id)
      }
      return tenant
    },

    get_vendor_by_id: async (_, { vendor_id }) => {
      const vendor = await models.vendor.findByPk(vendor_id, {
        include: {
          model: models.vendor_type,
          as: "vendor_type",
          attributes: ["vendor_title", "vendor_parent", "status"],
        },
      });

      if (!vendor) return null;

      return vendor.toJSON(); // vendor_type will be nested automatically
    },

    get_employee_shift_by_id: async (_, { employeeShiftId }) => {
      const shift = await models.employee_shift.findByPk(employeeShiftId)
      if (!shift) {
        console.warn('No shift found with ID:', employeeShiftId)
      }
      return shift
    },

    get_unpaid_invoices: async (_, { tenant_id }) => {
      try {
        if (!tenant_id) throw new Error("tenant_id is required");

        const invoices = await models.invoices.findAll({
          where: { status: { [Op.in]: ['unpaid', 'partial'] } },
          include: [
            {
              model: models.invoice_items,
              as: 'items',
            },
            {
              model: models.tenant_invoices,
              as: 'tenant_invoices',
              include: [
                {
                  model: models.tenants,
                  as: 'tenant',
                  attributes: ['id', 'first_name', 'last_name', 'corporation_name'],
                  where: { id: tenant_id },
                },
              ],
              required: true,
            },
          ],
          order: [['id', 'ASC']],
        });

        return invoices.map(inv => {
          const invoice = inv.toJSON();
          invoice.items = invoice.items?.map(item => ({
            ...item,
            name: item.title || 'Untitled',
          })) || [];

          if (invoice.tenant_invoices?.length > 0) {
            const tenantData = invoice.tenant_invoices[0].tenant;
            invoice.entity = {
              ...tenantData,
              __typename: 'TenantForInvoice',
            };
            invoice.tenant_id = tenantData.id;
            delete invoice.tenant_invoices;
          }

          return invoice;
        });
      } catch (error) {
        console.error('Error fetching unpaid invoices:', error);
        throw new Error('Failed to fetch unpaid invoices');
      }
    },

    get_unpaid_client_invoices: async (_, { client_id }) => {
      try {
        if (!client_id) throw new Error("client_id is required");

        const invoices = await models.invoices.findAll({
          where: { status: { [Op.in]: ['unpaid', 'partial'] } },
          include: [
            {
              model: models.invoice_items,
              as: 'items',
            },
            {
              model: models.client_invoices,
              as: 'client_invoices',
              include: [
                {
                  model: models.client,
                  as: 'client',
                  attributes: ['id', 'first_name', 'last_name'],
                  where: { id: client_id },
                },
              ],
              required: true,
            },
          ],
          order: [['id', 'ASC']],
        });

        return invoices.map(inv => {
          const invoice = inv.toJSON();
          invoice.items = invoice.items?.map(item => ({
            ...item,
            name: item.title || 'Untitled',
          })) || [];

          const clientData = invoice.client_invoices?.[0]?.client || {};
          invoice.entity = { ...clientData, __typename: 'ClientForInvoice' };
          invoice.client_id = clientData.id;
          delete invoice.client_invoices;

          return invoice;
        });
      } catch (error) {
        console.error('Error fetching unpaid client invoices:', error);
        throw new Error('Failed to fetch unpaid client invoices');
      }
    },

    get_tenant_contacts_by_id: async (_, { tenant_id }) => {

      const tenant_contacts = await models.tenant_contacts.findAll({
        where: {
          tenant_id: tenant_id
        }
      })
      if (!tenant_contacts || tenant_contacts.length === 0) {
        console.warn('No tenant contacts found with ID:', tenant_id)
      }
      return tenant_contacts
    },
    get_tenant_occupancy_by_id: async (_, { tenant_id }) => {
      const tenant_occupancy = await models.agreement.findAll({
        where: { tenant_id },
        include: [
          {
            model: models.property,
            as: 'property',
            attributes: ['id', 'name'], // or any other fields you want
          },
        ],
      });
      return tenant_occupancy;
    },
    get_all_tenant_occupancy: async () => {
      const all_tenant_occupancy = await models.agreement.findAll({
        include: [
          {
            model: models.property,
            as: 'property',
            attributes: ['id', 'name'],
          },
          {
            model: models.tenants,
            as: 'tenant',
            attributes: ['id', 'first_name', 'last_name', 'corporation_name', 'indi_corp_type'],
          },
        ],
      });
      return all_tenant_occupancy;
    },
    get_all_employee_shifts: async (_, { unit_id }) => {
      try {
        const shifts = await models.employee_shift.findAll({
          where: {
            shift_type: ['strict', 'flexible'],
            unit_id: unit_id,
          }
        });
        // Convert Sequelize instances to plain objects to avoid any internal Sequelize metadata
        return shifts.map(shift => shift.get({ plain: true }));
      } catch (error) {
        console.error('Error fetching employee shifts:', error);
        throw new Error('Failed to fetch employee shifts');
      }
    },
    get_all_employee_shifts_off: async (_, { unit_id }) => {
      try {
        const shifts = await models.employee_shift.findAll({
          where: {
            shift_type: ['strict', 'flexible', 'OFF'],
            unit_id: unit_id,
          }
        });
        // Convert Sequelize instances to plain objects to avoid any internal Sequelize metadata
        return shifts.map(shift => shift.get({ plain: true }));
      } catch (error) {
        console.error('Error fetching employee shifts:', error);
        throw new Error('Failed to fetch employee shifts');
      }
    },
    get_shift_rosters: async (_, { unit_id }) => {

      console.log('get_shift_rosters called for unit_id:', unit_id)

      const rosters = await models.shift_roster.findAll({
        where: { unit_id },

        include: [
          {
            model: models.employee,
            as: 'employee',
            attributes: ['id', 'firstname', 'lastname', 'social_security_num']
          },
          {
            model: models.employee_shift,
            as: 'employee_shift',
            attributes: ['id', 'shift_name', 'shift_type', 'color', 'office_start_time', 'office_end_time', 'flexible_total_hours', 'flexible_half_day_hours']
          }
        ]
      });

      return rosters.map(r => ({
        id: r.id,
        date: r.date,
        remarks: r.remarks,
        send_email: r.send_email,
        is_strict: r.is_strict,
        location: r.location,
        employee: r.employee ? [r.employee] : [], // array as per schema
        employee_shift: r.employee_shift ? [r.employee_shift] : []
      }));
    },

    get_attendance: async () => {

      const rosters = await models.employee_attendance.findAll({
        attributes: [
          'id', 'unit_id', 'employee_id', 'date', 'status',
          'clock_in_time', 'clock_out_time', 'working_from',
          'late', 'half_day', 'overwrite_attendance', 'added_by',
          'createdAt', 'updatedAt'
        ],
        include: [
          {
            model: models.unit,
            as: 'unit',
            attributes: ['id', 'name', 'company_name']
          },
          {
            model: models.employee,
            as: 'employee',
            attributes: ['id', 'firstname', 'lastname', 'social_security_num']
          }
        ]
      });

      return rosters;
    },

    get_employee_attendance: async (_, { employee_id }) => {
      const rosters = await models.employee_attendance.findAll({
        attributes: [
          'id', 'unit_id', 'employee_id', 'date', 'status',
          'clock_in_time', 'clock_out_time', 'working_from',
          'late', 'half_day', 'overwrite_attendance', 'added_by',
          'createdAt', 'updatedAt'
        ],
        include: [
          {
            model: models.unit,
            as: 'unit',
            attributes: ['id', 'name', 'company_name']
          },
          {
            model: models.employee,
            as: 'employee',
            attributes: ['id', 'firstname', 'lastname', 'social_security_num']
          }
        ],
        where: {
          employee_id: employee_id,
        }
      });
      return rosters;
    },

    get_projects: async (_, { unit_id }) => {

      console.log('get projects unit id', unit_id);

      const projects = await models.projects.findAll({
        where: { unit_id },
        attributes: [
          'id',
          'title',
          'estimated_hours',
          'priority',
          'start_date',
          'end_date',
          'summary',
          'team',
          'description',
        ],
      });

      const formattedProjects = await Promise.all(
        projects.map(async proj => {
          let teamDetails = [];
          if (proj.team) {
            const teamIds = proj.team.split(',');
            const employees = await models.employee.findAll({
              where: { id: teamIds },
              attributes: ['id', 'firstname', 'lastname', 'social_security_num'],
            });

            teamDetails = employees.map(emp => emp.get({ plain: true }));
          }

          return {
            id: proj.id,
            title: proj.title,
            estimated_hours: proj.estimated_hours,
            priority: proj.priority,
            start_date: proj.start_date,
            end_date: proj.end_date,
            summary: proj.summary,
            description: proj.description,
            team: teamDetails,
          };
        })
      );

      return formattedProjects;
    },

    get_tasks: async (_, { unit_id }) => {
      const tasks = await models.tasks.findAll({
        where: { unit_id },
        attributes: [
          'id',
          'title',
          'estimated_hours',
          'category',
          'start_date',
          'end_date',
          'status',
          'description',
        ],
        include: [
          {
            model: models.projects,
            as: 'projectInfo',
            attributes: ['id', 'title'],
          },
        ],
      });

      const formattedTasks = await Promise.all(
        tasks.map(async (task) => {

          const taskEmployees = await models.task_employee.findAll({
            where: { task_id: task.id },
            attributes: ['employee_id'],
          });


          const employeeIds = taskEmployees.map((te) => te.employee_id);


          let teamDetails = [];
          if (employeeIds.length > 0) {
            const employees = await models.employee.findAll({
              where: { id: { [Op.in]: employeeIds } },
              attributes: ['id', 'firstname', 'lastname', 'social_security_num', 'phone'],
            });
            teamDetails = employees.map((emp) => emp.get({ plain: true }));
          }

          return {
            id: task.id,
            title: task.title,
            estimated_hours: task.estimated_hours,
            category: task.category,
            project: task.projectInfo
              ? { id: task.projectInfo.id, title: task.projectInfo.title }
              : { id: 0, title: 'Unknown Project' },
            start_date: task.start_date,
            end_date: task.end_date,
            description: task.description,
            status: task.status,
            team: teamDetails,
          };
        })
      );

      return formattedTasks;
    },

    get_employee_tasks: async (_, { employee_id }) => {
      console.log('Fetching tasks for employee:', employee_id);
      try {
        // Fetch all task_employee records for the given employee_id with associated task and project data
        const taskEmployees = await models.task_employee.findAll({
          where: { employee_id },
          include: [
            {
              model: models.tasks,
              as: 'task',
              include: [
                {
                  model: models.projects,
                  as: 'projectInfo',
                  attributes: ['id', 'title'],
                },
              ],
            },
            {
              model: models.employee,
              as: 'employee',
              attributes: ['id', 'firstname', 'lastname', 'social_security_num', 'phone'],
            },
          ],
        });
        // Map the results to match the getEmployeeTaskResponse schema
        const employeeTasks = await Promise.all(
          taskEmployees.map(async (taskEmployee) => {
            const task = taskEmployee.task;

            // Fetch all team members for the current task
            const teamMembers = await models.task_employee.findAll({
              where: { task_id: task.id },
              include: [
                {
                  model: models.employee,
                  as: 'employee',
                  attributes: ['id', 'firstname', 'lastname', 'social_security_num', 'phone'],
                },
              ],
            });

            const dataToReturn = {
              id: task.id,
              unit_id: task.unit_id,
              title: task.title,
              estimated_hours: task.estimated_hours,
              category: task.category,
              project: task.projectInfo
                ? {
                  id: task.projectInfo.id,
                  title: task.projectInfo.title,
                }
                : null,
              start_date: task.start_date,
              end_date: task.end_date,
              status: task.status,
              description: task.description,
              team: teamMembers.map((te) => ({
                id: te.employee.id,
                firstname: te.employee.firstname,
                lastname: te.employee.lastname,
                social_security_num: te.employee.social_security_num,
                phone: te.employee.phone,
              })),
              created_by: task.created_by,
              createdAt: task.createdAt,
              updatedAt: task.updatedAt,
            };
            console.log("dataToReturn 1111:", dataToReturn)
            return dataToReturn;
          })
        );

        console.log("employeeTasks 123 :", employeeTasks)

        // Remove duplicates by task ID
        const uniqueTasks = Array.from(
          new Map(employeeTasks.map((task) => [task.id, task])).values()
        );

        return uniqueTasks;
      } catch (error) {
        console.error('Error fetching tasks for employee:', error);
        throw new Error(`Failed to fetch tasks for employee ID ${employee_id}`);
      }
    },

    get_time_sheet: async (_, { user_id, unit_id, task_id }) => {
      console.log('Fetching timesheet for employee:', user_id);
      try {
        // Fetch all task_employee records for the given employee_id with associated employee data
        const taskEmployees = await models.project_time_logs.findAll({
          where: { unit_id, task_id },
          include: {
            model: models.user,
            as: 'user',
            attributes: ['id', 'name'],
          },
        });

        // Map the results to match the getEmployeeTimeSheetResponse schema
        return taskEmployees.map((taskEmployee) => ({
          employee: {
            id: taskEmployee.user.id ? taskEmployee.user.id : null,
            name: taskEmployee.user.name ? taskEmployee.user.name : null,
          },
          start_time: taskEmployee.start_time ? taskEmployee.start_time : null,
          end_time: taskEmployee.end_time ? taskEmployee.end_time : null,
          total_time: taskEmployee.total_time ? taskEmployee.total_time : null,
          memo: taskEmployee.memo ? taskEmployee.memo : null,
        }));
      } catch (error) {
        console.error('Error fetching timesheet for employee:', error);
        throw new Error(`Failed to fetch timesheet for employee ID ${user_id}`);
      }
    },

    get_task_history: async (_, { user_id, unit_id, task_id }) => {
      try {

        const taskHistory = await models.task_history.findAll({
          where: { unit_id, task_id },
          include: [
            {
              model: models.user,
              as: 'user',
              attributes: ['name'],
            },
          ],
          order: [['created_at', 'DESC']],
        });
        return taskHistory.map(record => ({
          id: record.id,
          unit_id: record.unit_id,
          task_id: record.task_id,
          sub_task_id: record.sub_task_id,
          employee_id: record.employee_id,
          details: record.details,
          created_by: record.created_by,
          created_at: record.created_at.toISOString(),
          employee: record.user ? {
            name: record.user.name,
          } : null,

        }));
      } catch (error) {
        console.error('Failed to fetch task history:', error.message);
        throw new Error(`Failed to fetch task history: ${error.message}`);
      }
    },

    get_task_by_id: async (_, { employee_id }) => {
      console.log('Fetching tasks for employee:', employee_id);
      try {
        // Fetch all task_employee records for the given employee_id with associated task and project data
        const taskEmployees = await models.task_employee.findAll({
          where: { employee_id },
          include: [
            {
              model: models.tasks,
              as: 'task',
              include: [
                {
                  model: models.projects,
                  as: 'projectInfo',
                  attributes: ['id', 'title'],
                },
              ],
            },
            {
              model: models.employee,
              as: 'employee',
              attributes: ['id', 'firstname', 'lastname', 'social_security_num', 'phone'],
            },
          ],
        });

        // Map the results to match the getEmployeeTaskResponse schema
        const employeeTasks = await Promise.all(
          taskEmployees.map(async (taskEmployee) => {
            const task = taskEmployee.task;

            // Fetch all team members for the current task
            const teamMembers = await models.task_employee.findAll({
              where: { task_id: task.id },
              include: [
                {
                  model: models.employee,
                  as: 'employee',
                  attributes: ['id', 'firstname', 'lastname', 'social_security_num', 'phone'],
                },
              ],
            });

            return {
              id: task.id,
              unit_id: task.unit_id,
              title: task.title,
              estimated_hours: task.estimated_hours,
              category: task.category,
              project: task.projectInfo
                ? {
                  id: task.projectInfo.id,
                  title: task.projectInfo.title,
                }
                : null,
              start_date: task.start_date,
              end_date: task.end_date,
              status: task.status,
              description: task.description,
              team: teamMembers.map((te) => ({
                id: te.employee.id,
                firstname: te.employee.firstname,
                lastname: te.employee.lastname,
                social_security_num: te.employee.social_security_num,
                phone: te.employee.phone,
              })),
              created_by: task.created_by,
              createdAt: task.createdAt,
              updatedAt: task.updatedAt,
            };
          })
        );

        // Remove duplicates by task ID
        const uniqueTasks = Array.from(
          new Map(employeeTasks.map((task) => [task.id, task])).values()
        );

        return uniqueTasks;
      } catch (error) {
        console.error('Error fetching tasks for employee:', error);
        throw new Error(`Failed to fetch tasks for employee ID ${employee_id}`);
      }
    },

    get_swap_task: async () => {
      try {
        const swap_task = await models.task_approved.findAll()


        return swap_task;

      } catch (err) {
        console.error('Error fetching Task Approved:', err)
        throw new Error('Failed to fetch tasks')
      }
    },


    // get_task_approved_by_id: async (_, { id }) => {
    //   try {
    //     return await TaskApproved.findByPk(id)
    //   } catch (err) {
    //     console.error('Error fetching TaskApproved by ID:', err)
    //     throw new Error('Failed to fetch task by ID')
    //   }
    // },

    get_clients: async (_, { unit_id }) => {
      try {
        const clients = await models.client.findAll({
          where: { unit_id },
          attributes: [
            "id",
            "first_name",
            "last_name",
            "email",
            "phone",
            "ssn",
            "city",
            "state",
            "country",
            "status",
          ],
        });

        // format if needed (plain objects)
        return clients.map((client) => client.get({ plain: true }));
      } catch (err) {
        console.error("Error fetching clients:", err);
        throw new Error("Failed to fetch clients");
      }
    },

    get_client_entity: async (_, { client_id }) => {
      try {
        const entities = await models.client_entity.findAll({
          attributes: [
            "id",
            "client_id",
            "entity_name",
            "entity_ein",
            "email",
            "service_id",
            "phone",
            "street_number",
            "suite_floor",
            "zip_code",
            "city",
            "state",
            "country",
          ],
          where: { client_id },
        });

        return entities.map((entity) => entity.get({ plain: true }));
      } catch (err) {
        console.error("Error fetching client entities:", err);
        throw new Error("Failed to fetch client entities");
      }
    },

    get_services: async (_, { unit_id }) => {
      try {
        const services = await models.client_service.findAll({
          where: { unit_id },
          attributes: [
            "id",
            "code",
            "name",
            "price",
            "status",
            "description",
          ],
        });

        return services.map((service) => service.get({ plain: true }));
      } catch (err) {
        console.error("Error fetching client service:", err);
        throw new Error("Failed to fetch client service");
      }
    },

    get_global_currency: async (_, { unit_id }) => {
      try {
        const currencies = await models.global_currency.findAll({
          where: {
            unit_id: unit_id,
          }
        });

        if (!currencies || currencies.length === 0) {
          console.warn('No global currencies found');
        }

        return currencies;
      } catch (err) {
        console.error('Error fetching currencies:', err);
        throw new Error('Failed to fetch currencies');
      }
    },

    get_packages: async (_parent, { unit_id }) => {
      try {
        if (!unit_id || isNaN(unit_id)) {
          console.warn(`Invalid unit_id provided: ${unit_id}`);
          return [];
        }

        console.log("unit_id in packages:", unit_id);
        const packages = await models.package.findAll({
          where: { unit_id: unit_id },
          include: [
            {
              model: models.global_currency,
              as: 'currency',
            },
          ],
        });

        if (!packages || packages.length === 0) {
          console.warn(`No packages found for unit_id ${unit_id}`);
          return [];
        }

        const mappedPackages = packages.map((pkg) => ({
          id: pkg.id,
          name: pkg.name,
          plan_type: pkg.plan_type,
          maxEmployees: pkg.max_employees,
          maxStorageSize: pkg.max_storage_size,
          storage_unit: pkg.storage_unit,
          position: pkg.sort,
          isPrivate: Boolean(pkg.is_private),
          isRecommended: Boolean(pkg.is_recommended),
          currency: pkg.currency
            ? {
              id: pkg.currency.id,
              currency_name: pkg.currency.currency_name,
              currency_symbol: pkg.currency.currency_symbol,
            }
            : null,
          hasMonthlyPlan: pkg.monthly_price > 0,
          monthlyPrice: pkg.monthly_price,
          hasAnnualPlan: pkg.annual_price > 0,
          annualPrice: pkg.annual_price,
          description: pkg.description,
          modules: (() => {
            try {
              return pkg.module_in_package ? JSON.parse(pkg.module_in_package) : [];
            } catch (e) {
              console.error("Error parsing modules:", e);
              return [];
            }
          })(),
        }));

        return mappedPackages;
      } catch (err) {
        console.error('Error fetching packages:', err);
        throw new Error('Failed to fetch packages');
      }
    },

    get_temporary_employees: async (_, { unit_id }) => {
      try {
        const employees = await models.temporary_employee.findAll({
          where: {
            unit_id: unit_id,
          }
        });

        if (!employees || employees.length === 0) {
          console.warn('No temporary employees found');
          return [];
        }

        const mappedEmployees = employees.map(emp => ({
          id: emp.id,
          first_name: emp.first_name,
          middle_name: emp.middle_name,
          last_name: emp.last_name,
          ssn: emp.ssn,
          email: emp.email,
          phone_number: emp.phone_number,
          emergency_phone_number: emp.emergency_phone_number,
          number_and_street: emp.number_and_street,
          suite_floor: emp.suite_floor,
          zip_code: emp.zip_code,
          city: emp.city,
          state: emp.state,
          country: emp.country,
          borough: emp.borough,
          block: emp.block,
          lot: emp.lot,
          gender: emp.gender,
          id_type: emp.id_type,
          id_docs: emp.id_docs,
          status: emp.status,
          message: emp.message,
          created_by: emp.created_by,
          created_at: emp.created_at,
          updated_at: emp.updated_at
        }));

        return mappedEmployees;

      } catch (err) {
        console.error('Error fetching temporary employees:', err);
        throw new Error('Failed to fetch temporary employees');
      }
    },

    get_vendorType: async (_, { unit_id }) => {
      try {

        const vendorTypes = await models.vendor_type.findAll({
          where: { unit_id },
          order: [['id', 'DESC']],
        });

        if (!vendorTypes || vendorTypes.length === 0) {
          console.warn('No vendor types found')
          return []
        }

        const mappedVendorTypes = vendorTypes.map(vt => ({
          id: vt.id,
          vendor_title: vt.vendor_title,
          vendor_parent: vt.vendor_parent,
          status: vt.status
        }))

        return mappedVendorTypes
      } catch (err) {
        console.error('Error fetching vendor types:', err)
        throw new Error('Failed to fetch vendor types')
      }
    },

    getEmployeeId: async (_, { user_id }) => {
      try {
        const data = await models.user_employee_map.findOne({
          where: { user_id: user_id },
        });
        console.log(data, "get employee id");
        if (!data) {
          throw new Error("Employee ID not found");
        }
        return { employee_id: data.employee_id };
      } catch (err) {
        console.error("Error fetching data:", err);
        throw new Error("Failed to fetch employee ID");
      }
    },

    // Updated server-side resolver
    getUnitId: async (_, { login_employee_id }) => {
      try {
        const data = await models.employee.findOne({
          where: { id: login_employee_id },
        });
        console.log(data, "get unit id");
        if (!data) {
          throw new Error("Unit ID not found");
        }
        return { unitId: data.unit_id };
      } catch (err) {
        console.error("Error fetching data:", err);
        throw new Error("Failed to fetch unit ID");
      }
    },

    get_vendors: async (_, { unit_id }) => {
      try {
        const vendors = await models.vendor.findAll({
          where: { unit_id },
          order: [['id', 'DESC']],
        });

        if (!vendors || vendors.length === 0) {
          console.warn('No vendors found');
          return [];
        }

        // Map DB results to match full Vendor type
        const mappedVendors = vendors.map(v => ({
          id: v.id,
          vendor_name: v.vendor_name,
          opening_balance: v.opening_balance,
          as_of_date: v.as_of_date,
          date_of_birth: v.date_of_birth,
          company_name: v.company_name,
          name_prefix: v.name_prefix,
          first_name: v.first_name,
          middle_initial: v.middle_initial,
          last_name: v.last_name,
          job_title: v.job_title,
          phone: v.phone,
          work_phone: v.work_phone,
          mobile: v.mobile,
          fax: v.fax,
          email: v.email,
          cc_email: v.cc_email,
          website: v.website,
          other: v.other,
          billed_street: v.billed_street,
          billed_suite: v.billed_suite,
          billed_zip: v.billed_zip,
          billed_city: v.billed_city,
          billed_state: v.billed_state,
          shipped_street: v.shipped_street,
          shipped_suite: v.shipped_suite,
          shipped_zip: v.shipped_zip,
          shipped_city: v.shipped_city,
          shipped_state: v.shipped_state,
          vendor_type_id: v.vendor_type_id,
          status: v.status
        }));

        return mappedVendors;
      } catch (err) {
        console.error('Error fetching vendors:', err);
        throw new Error('Failed to fetch vendors');
      }
    },
    get_vendor_payment: async (_, { vendor_id }) => {
      try {
        const vendorPayment = await models.vendor_payment.findOne({
          where: { vendor_id }
        });

        if (!vendorPayment) return null;

        return {
          id: vendorPayment.id,
          account_no: vendorPayment.account_no,
          vendor_id: vendorPayment.vendor_id,
          credit_limit: vendorPayment.credit_limit,
          print_name_on_check_as: vendorPayment.print_name_on_check_as, // ✅ fixed
          payment_terms_id: vendorPayment.payment_terms_id
        };
      } catch (err) {
        console.error('Sequelize error fetching vendor payment:', err);
        throw err;
      }
    },
    get_vendor_tax: async (_, { vendor_id }) => {
      try {
        const vendorTax = await models.vendor_tax.findOne({ where: { vendor_id } });
        if (!vendorTax) return null;

        return {
          id: vendorTax.id,
          tax_id: vendorTax.tax_id,
          vendor_id: vendorTax.vendor_id,
          is_1099_eligible: vendorTax.is_1099_eligible,
        };
      } catch (err) {
        console.error('Sequelize error fetching vendor tax:', err);
        throw err;
      }
    },
    get_payment_terms: async () => {
      try {
        const paymentTerms = await models.payment_term.findAll();

        if (!paymentTerms || paymentTerms.length === 0) {
          console.warn("No payment terms found");
          return [];
        }

        return paymentTerms.map(term => ({
          id: term.id,
          term_name: term.term_name,
          term_type: term.term_type,
          is_inactive: term.is_inactive,
          net_due_days: term.net_due_days,
          discount_percent: term.discount_percent,
          discount_if_paid_within_days: term.discount_if_paid_within_days,
          net_due_day_of_month: term.net_due_day_of_month,
          due_next_month_if_within_days: term.due_next_month_if_within_days,
          date_driven_discount_percent: term.date_driven_discount_percent,
          discount_if_paid_before_day: term.discount_if_paid_before_day,
          created_by: term.created_by,
          updated_by: term.updated_by,
          created_at: term.created_at,
          updated_at: term.updated_at,
        }));
      } catch (err) {
        console.error("Error fetching payment terms:", err);
        throw new Error("Failed to fetch payment terms");
      }
    },
    get_tenant_document_by_id: async (_, { tenant_id }) => {
      const tenant_documents = await models.tenant_documents.findAll({
        where: {
          tenant_id: tenant_id
        }
      })
      if (!tenant_documents || tenant_documents.length === 0) {
        console.warn('No tenant documents found with ID:', tenant_id)
      }
      return tenant_documents
    },
    get_property_items_by_id: async (_, { property_id }) => {
      const propertyItems = await models.property_item.findAll({
        where: {
          property_id: property_id
        }
      })
      if (!propertyItems || propertyItems.length === 0) {
        console.warn('No property items found with ID:', property_id)
      }
      return propertyItems
    },
    get_property_taxes_by_id: async (_, { property_id }) => {
      const propertyTaxes = await models.property_tax.findAll({
        where: {
          property_id: property_id
        }
      })
      if (!propertyTaxes || propertyTaxes.length === 0) {
        console.warn('No property items found with ID:', property_id)
      }
      return propertyTaxes
    },
    get_property_docs_by_id: async (_, { ref_id }) => {
      const propertyDocs = await models.document.findAll({
        where: {
          ref_id: ref_id
        }
      })
      if (!propertyDocs || propertyDocs.length === 0) {
        console.warn('No property items found with ID:', ref_id)
      }
      return propertyDocs
    },
    is_tenant_contact_email_exist: async (_, { email }, context) => {
      const contact = await context.models.tenant_contacts.findOne({
        where: { email }
      })
      return !!contact
    },
    get_agreement_items_by_contract_id: async (_, { occupancy_id }) => {
      const agreement = await models.agreement.findOne({
        where: { id: occupancy_id },
      });

      const agreementItems = await models.agreement_items.findAll({
        where: { agreement_id: occupancy_id },
      });

      return {
        agreement,
        items: agreementItems,
      };
    },
    get_agreement_items_by_tenant_id: async (_, { tenant_id }) => {
      const agreement = await models.agreement.findOne({
        where: { tenant_id },
      });

      if (!agreement) {
        return { agreement: null, items: [] };
      }

      const agreementItems = await models.agreement_items.findAll({
        where: { agreement_id: agreement.id },
      });

      return {
        agreement,
        items: agreementItems,
      };
    },

    get_subtasks_by_task: async (_, { employee_id, unit_id, task_id }) => {
      try {
        if (!task_id) throw new Error('Task ID is required');

        const subtasks = await models.sub_tasks.findAll({
          where: {
            unit_id,
            task_id
          },
          order: [['id', 'ASC']],
          include: [
            {
              model: models.tasks,
              as: 'task',
            },
            {
              model: models.employee,
              as: 'assignedTo',
              attributes: ['id', 'firstname', 'lastname'],
            },
            {
              model: models.user,
              as: 'assignedBy',
              attributes: ['id', 'name'],
            },
          ],
        });

        return subtasks;
      } catch (error) {
        console.error('Error fetching subtasks:', error);
        throw new Error('Failed to fetch subtasks');
      }
    },



    get_task_comments: async (_, { user_id, unit_id, task_id }) => {
      try {
        const comments = await models.task_comments.findAll({
          where: { unit_id, task_id },
          include: [
            {
              model: models.user,
              as: 'author',
              attributes: ['id', 'name'],
            },
          ],
          order: [['id', 'DESC']],
        });

        // Enrich each comment with reaction counts and the current user's reaction
        const enrichedComments = await Promise.all(
          comments.map(async (comment) => {
            const commentData = comment.toJSON();

            // Count likes and dislikes
            const likes = await models.task_comment_emoji.count({
              where: { comment_id: comment.id, emoji_name: 'thumbs-up' },
            });

            const dislikes = await models.task_comment_emoji.count({
              where: { comment_id: comment.id, emoji_name: 'thumbs-down' },
            });

            // Check if current user reacted
            const userReaction = await models.task_comment_emoji.findOne({
              where: { comment_id: comment.id, user_id },
              attributes: ['emoji_name'],
            });

            return {
              ...commentData,
              likes,
              dislikes,
              userReaction: userReaction ? userReaction.emoji_name : null,
            };
          })
        );

        return enrichedComments;
      } catch (error) {
        console.error('Error fetching task comments:', error);
        throw new Error('Failed to fetch task comments');
      }
    },


    get_task_notes: async (_, { user_id, unit_id, task_id }) => {
      try {
        const notes = await models.task_notes.findAll({
          where: {
            unit_id,
            task_id
          },
          include: [
            {
              model: models.user,
              as: 'author',
              attributes: ['id', 'name'],
            },
          ],
          order: [['id', 'DESC']],
        });

        return notes;
      } catch (error) {
        console.error('Error fetching task notes:', error);
        throw new Error('Failed to fetch task notes');
      }
    },

    verifyUserToken: async (_, { token }) => {
      const { valid, decoded, error } = verifyToken(token);

      if (!valid) {
        return { success: false, message: `Invalid or expired token: ${error}`, user: null };
      }

      const user = await models.user.findByPk(decoded.userId, { raw: true });
      if (!user) {
        return { success: false, message: 'User not found', user: null };
      }

      return {
        success: true,
        message: 'Token verified successfully',
        user: {
          user_id: user.id,
          name: user.name,
          email: user.email,
        },
      };
    },

  },

  Mutation: {
    // login: async (_, { email, password }, { req }) => {
    //   const attempt = await models.login_attempt.findOne({ where: { email: email }})
    //   let attemptCount = 0
    //   if (attempt) {
    //     if (attempt.count > 3) {
    //       throw new Error('Too many bad attempts')
    //     }
    //     attemptCount = attempt.count
    //   }
    //   var verifyOptions = {
    // 		issuer: 'authorizaxtion/resource/ar/server',
    // 		subject: 'argroup', 
    // 		audience: 'login',
    //     maxAge: '12h',
    //     algorithms: ['RS256']
    //   }
    //   const usernameTokan = jwt.verify(email, PUBLIC_KEY, verifyOptions)
    //   const passwordToken = jwt.verify(password, PUBLIC_KEY, verifyOptions)
    //   const user = await models.user.findOne({ where: { email: usernameTokan.username, status: 'Active' }})
    //   const user_pass = await bcrypt.hash(user.user_pass, 10)
    //   if (user) {
    //     if (bcrypt.compareSync(passwordToken.password, user_pass)) {
    //       const userAccessFlags = await models.user_access_flag.findOne({ where: { user_id: user.id }})
    //       let accessFlags = 255
    //       if (userAccessFlags) {
    //         accessFlags = userAccessFlags.access_flags
    //       }
    //       await models.login_attempt.upsert({email: usernameTokan.username, count: 0}) 
    //       return {
    //         id: user.id,
    //         name: user.name,
    //         nick: user.nick,
    //         email: user.email,
    //         user_group_id: user.user_group_id,
    //         access_flags: accessFlags,
    //         token: jwt.sign({ userId: user.id }, process.env.JWT_SECRET)
    //       }
    //     }
    //     await models.login_attempt.upsert({email: usernameTokan.username, count: attemptCount + 1}) 
    //     throw new Error('Incorrect password')
    //   }
    //   await models.login_attempt.upsert({email: usernameTokan.username, count: attemptCount + 1}) 
    //   throw new Error('No Such User exists')
    // },


    login: async (_, { email, password }, { req }) => {

      console.log('login function in resolver', email);

      const attempt = await models.login_attempt.findOne({ where: { email } });
      let attemptCount = 0;
      // if (attempt) {
      //   if (attempt.count > 3) {
      //     throw new Error('Too many bad attempts');
      //   }
      //   attemptCount = attempt.count;
      // }

      const user = await models.user.findOne({ where: { email, status: 'Active' } });


      if (!user) {
        await models.login_attempt.upsert({ email, count: attemptCount + 1 });
        throw new Error('No such user exists');
      }
      console.log('login user Access user id', user.id);

      const isHashed = user.password.startsWith('$2');

      let isPasswordValid = false;
      if (isHashed) {
        isPasswordValid = bcrypt.compareSync(password, user.password);
      } else {
        isPasswordValid = password === user.password;
      }

      if (!isPasswordValid) {
        await models.login_attempt.upsert({ email, count: attemptCount + 1 });
        throw new Error('Incorrect password');
      }

      await models.login_attempt.upsert({ email, count: 0 });

      const userAccessFlags = await models.user_access_flag.findOne({ where: { user_id: user.id } });

      const accessFlags = userAccessFlags ? userAccessFlags.access_flags : 255;

      const payload = {
        userId: user.id,
        email: user.email,
        accessFlags
      };
      const signOptions = {
        issuer: 'authorizaxtion/resource/ar/server',
        subject: 'argroup',
        audience: 'login',
        expiresIn: '12h',
        algorithm: 'HS256'
      };

      const token = jwt.sign(payload, process.env.JWT_SECRET, signOptions);

      console.log("token hit :", token)
      return {
        id: user.id,
        name: user.name,
        nick: user.nick,
        email: user.email,
        user_group_id: user.user_group_id,
        access_flags: accessFlags,
        token
      };
    },

    signup: async (_, { username, email, password, otp }, { req }) => {
      try {
        console.log(' Signup function in resolver', { username, email, otp });

        const invitation = await models.invitation.findOne({
          where: { email: email },
          order: [['created_at', 'DESC']], // latest record
        });

        if (!invitation) {
          return {
            success: false,
            message: 'No invitation found for this email address'
          };
        }

        // 2️⃣ Verify OTP
        if (invitation.otp_code !== otp) {
          return {
            success: false,
            message: 'Invalid OTP code'
          };
        }

        // 3️⃣ Check if email already exists in temporary_employees
        const existingEmployee = await models.temporary_employee.findOne({
          where: { email: email },
        });

        if (existingEmployee) {
          return {
            success: false,
            message: 'This email is already registered. Please login instead.'
          };
        }

        // 4️⃣ Check if email exists in main users table
        const existingUser = await models.user.findOne({
          where: { email: email },
        });

        if (existingUser) {
          return {
            success: false,
            message: 'This email is already registered. Please login instead.'
          };
        }

        // 5️⃣ Save into temporary_employee with unit_id from invitation
        const newEmployee = await models.temporary_employee.create({
          first_name: username,
          email: email,
          user_pass: password,
          password: password,
          unit_id: invitation.unit_id,
          device_id: null,
          device_model: 'Web',
          device_operating_system: 'Web Browser',
          status: 0, // pending status
        });

        // 6️⃣ Reset login attempts
        const existingAttempt = await models.login_attempt.findOne({
          where: { email: email },
        });

        if (existingAttempt) {
          await existingAttempt.update({ count: 0 });
        } else {
          await models.login_attempt.create({ email: email, count: 0 });
        }

        console.log('✅ Signup successful for temporary employee:', newEmployee.id);

        // Return simple success response with waiting message
        return {
          success: true,
          message: 'Your registration request has been submitted. We will approve it within 1-2 days.'
        };

      } catch (error) {
        console.error('❌ Error in signup:', error);

        // Catch unique constraint error
        if (error.name === 'SequelizeUniqueConstraintError') {
          return {
            success: false,
            message: 'This email is already registered. Please login instead.'
          };
        }

        return {
          success: false,
          message: error.message || 'Failed to register user'
        };
      }
    },

    logout: (_, args, { auth }) => {
      return true
    },

    change_user_password: async (_, { email, oldPassword, newPassword }, { auth }) => {
      const user = await models.user.findOne({ where: { email } })
      const user_pass = await bcrypt.hash(user.user_pass, 10)
      if (user) {
        if (bcrypt.compareSync(oldPassword, user_pass)) {
          await models.user.update({ user_pass: newPassword }, { where: { email } })
          await models.login_attempt.upsert({ email: email, count: 0 })
          return true
        }
        throw new Error('Incorrect old password')
      }
      throw new Error('No Such User exists')


    },

    employee_entry: async (_, { employeeInput }, { auth }) => {
      const user = await models.user.findOne({
        where: {
          id: auth.userId
        }
      })
      if (!user) {
        return false
      }
      let employee = employeeInput.id ? await models.employee.findByPk(employeeInput.id) : null
      if (employee) {
        let type = ''
        let changeTitle = ''
        let changeDescription = ''
        if (!employee.termination_date && employeeInput.termination_date) {
          type = 'Terminated'
        }
        if (!employee.rehire_date && employeeInput.rehire_date) {
          type = 'Rehired'
        }
        if (employee.exemptions !== employeeInput.exemptions) {
          type = 'Changed'
          changeTitle = 'Exemptions'
          changeDescription = employeeInput.exemptions
        }
        if (Math.abs(employee.wage - employeeInput.wage) > 0.01) {
          type = 'Changed'
          changeTitle += changeTitle ? ',Wage/Salary' : 'Wage/Salary'
          changeDescription = employeeInput.wage
        }
        if (employee.type !== employeeInput.type) {
          type = 'Changed'
          changeTitle += changeTitle ? ',Type' : 'Type'
          changeDescription = employeeInput.type
        }
        if (employee.department_id !== employeeInput.department_id) {
          type = 'Changed'
          changeTitle += changeTitle ? ',Department' : 'Department'
          changeDescription = employeeInput.department_id
        }
        if (employee.social_security_num !== employeeInput.social_security_num) {
          type = 'Changed'
          changeTitle += changeTitle ? ',Social Security' : 'Social Security'
          changeDescription = employeeInput.social_security_num
        }
        if (employee.firstname !== employeeInput.firstname) {
          type = 'Changed'
          changeTitle += changeTitle ? ',Firstname' : 'Firstname'
          changeDescription = employeeInput.firstname
        }
        if (employee.middlename !== employeeInput.middlename) {
          type = 'Changed'
          changeTitle += changeTitle ? ',Middlename' : 'Middlename'
          changeDescription = employeeInput.middlename
        }
        if (employee.lastname !== employeeInput.lastname) {
          type = 'Changed'
          changeTitle += changeTitle ? ',Lastname' : 'Lastname'
          changeDescription = employeeInput.Lastname
        }
        if (employee.birth_date !== employeeInput.birth_date) {
          type = 'Changed'
          changeTitle += changeTitle ? ',Birth Date' : 'Birth Date'
          changeDescription = employeeInput.birth_date
        }
        if (employee.hire_date !== employeeInput.hire_date) {
          type = 'Changed'
          changeTitle += changeTitle ? ',Hire Date' : 'Hire Date'
          changeDescription = employeeInput.hire_date
        }
        if (employee.payroll_id !== employeeInput.payroll_id) {
          type = 'Changed'
          changeTitle += changeTitle ? ',Payroll Id' : 'Payroll Id'
          changeDescription = employeeInput.payroll_id
        }
        if (employee.job_title !== employeeInput.job_title) {
          type = 'Changed'
          changeTitle += changeTitle ? ',Job Title' : 'Job Title'
          changeDescription = employeeInput.job_title
        }
        if (employee.address !== employeeInput.address
          || employee.city !== employeeInput.city
          || employee.state !== employeeInput.state
          || employee.zip !== employeeInput.zip) {
          type = 'Changed'
          changeTitle += changeTitle ? ',Address' : 'Address'
          changeDescription = employeeInput.address
        }

        await models.employee.upsert(employeeInput)
        await models.employee_change.create({
          unit_id: employeeInput.unit_id,
          employee_id: employeeInput.id,
          type: type,
          emp_type: employeeInput.type,
          change_title: changeTitle,
          change_desc: changeDescription
        })
        await models.employee_log.create({
          employee_id: employeeInput.id,
          log: `Employee updated by ${user.name}`
        })
      } else {
        delete employeeInput.id
        const duplicatePayrollIdEmployee = await models.employee.findOne({
          where: {
            unit_id: employeeInput.unit_id,
            payroll_id: employeeInput.payroll_id
          }
        })
        if (duplicatePayrollIdEmployee) {
          const nextPayrollId = await models.employee.findOne({
            attributes: [
              [sequelize.literal('cast((max(cast(`payroll_id` as unsigned)) + 1) as char)'), 'next_payroll_id']
            ],
            where: {
              unit_id: employeeInput.unit_id
            }
          })
          employeeInput.payroll_id = nextPayrollId.dataValues.next_payroll_id || employeeInput.payroll_id
        }
        await models.employee.create(employeeInput)
          .then(async result => {
            await models.employee_change.create({
              unit_id: employeeInput.unit_id,
              employee_id: result.id,
              type: 'New',
              emp_type: employeeInput.type
            })
            await models.employee_log.create({
              employee_id: result.id,
              log: `Employee added by ${user.name}`
            })
          })
      }
      return true
    },
    employee_delete: async (_, { employeeId }, { auth }) => {
      const user = await models.user.findOne({
        where: {
          id: auth.userId
        }
      })
      if (!user) {
        return false
      }
      let employee = employeeId ? await models.employee.findByPk(employeeId) : null
      if (employee) {
        await models.employee.destroy({
          where: {
            id: employeeId
          }
        })
      }
      return true
    },
    employee_change_delete: async (_, { employeeChangeId }, { auth }) => {
      const user = await models.user.findOne({
        where: {
          id: auth.userId
        }
      })
      if (!user) {
        return false
      }
      await models.employee_change.update({
        deletedAt: moment().format("YYYY-MM-DD HH:mm:ss")
      },
        {
          where: {
            id: employeeChangeId
          }
        })
      return true
    },

    update_employee_by_id: async (_, { employeeUpdateInput }) => {
      const { id, ...updateFields } = employeeUpdateInput;

      console.log('update employee by id', updateFields);

      try {
        await models.employee.update(updateFields, {
          where: { id }
        });
        return true;
      } catch (error) {
        console.error("Error updating employee:", error);
        return false;
      }
    },


    sales_entry: async (_, { saleInput }, { auth }) => {
      return await models.sequelize.transaction({ type: sequelize.Transaction.TYPES.EXCLUSIVE }, async transaction => {
        const user = await models.user.findOne(
          {
            where: {
              id: auth.userId
            }
          },
          { transaction }
        )
        if (!user) {
          return false
        }
        await models.sale.findOne({
          where: {
            sales_date: saleInput.sales_date,
            unit_id: saleInput.unit_id
          },
          transaction,
          lock: transaction.LOCK
        }).then(async sale => {
          if (sale) {
            const totalExpense = await models.sales_expense.findOne({
              attributes: [
                [sequelize.fn('SUM', sequelize.col('amount')), 'total_amount']
              ],
              where: {
                sale_id: saleInput.id
              }
            }, { transaction })
            const totalExpenseAmount = totalExpense.dataValues.total_amount || 0.0
            const totalDesopit = await models.sales_deposit.findOne({
              attributes: [
                [sequelize.fn('SUM', sequelize.col('amount')), 'total_amount']
              ],
              where: {
                sale_id: saleInput.id
              }
            }, { transaction })
            const totalDesopitAmount = totalDesopit.dataValues.total_amount || 0.0
            saleInput.cash_in_hand = saleInput.cash - totalExpenseAmount - totalDesopitAmount
            delete saleInput.id
            await sale.update(saleInput, { transaction })
            await models.sales_log.create(
              {
                sale_id: sale.id,
                log: `Daily Sales Sheet updated by ${user.name}`
              },
              { transaction }
            )
          } else {
            delete saleInput.id
            const result = await models.sale.create(
              {
                ...saleInput,
                cash_in_hand: saleInput.cash
              },
              { transaction }
            )
            await models.sales_log.create(
              {
                sale_id: result.id,
                log: `Daily Sales Sheet addeded by ${user.name}`
              },
              { transaction }
            )
          }
        })
        return true
      }).catch(error => {
        return false
      })
    },
    sales_deposit_entry: async (_, args, { auth }) => {
      const user = await models.user.findOne({
        where: {
          id: auth.userId
        }
      })
      if (!user) {
        return false
      }
      const sale = await models.sale.findOne({
        where: {
          id: args.depositInput.sale_id
        }
      })
      if (sale) {
        const id = args.depositInput.id || -1
        delete args.depositInput.id
        var deposit
        if (id >= 0) {
          deposit = await models.sales_deposit.findOne({
            where: {
              id: id
            }
          })
        }
        if (deposit) {
          delete args.depositInput.sale_id
          await models.sales_deposit.update(args.depositInput,
            {
              where: {
                id: id
              }
            }
          )
          await models.sales_log.create(
            {
              sale_id: sale.id,
              log: `Deposit "${args.depositInput.bank_title}" for $${args.depositInput.amount} updated by ${user.name}`
            }
          )
        }
        else {
          await models.sales_deposit.create(args.depositInput)
          await models.sales_log.create(
            {
              sale_id: sale.id,
              log: `Deposit "${args.depositInput.bank_title}" for $${args.depositInput.amount} added by ${user.name}`
            }
          )
        }
        await updateCashInHand(sale)
        return true
      }
      return false
    },
    sales_deposit_delete: async (_, args, { auth }) => {
      const user = await models.user.findOne({
        where: {
          id: auth.userId
        }
      })
      if (!user) {
        return false
      }
      const sale = await models.sale.findOne({
        where: {
          id: args.depositInput.sale_id
        }
      })
      if (sale) {
        await models.sales_log.create(
          {
            sale_id: sale.id,
            log: 'Deposit "' + args.depositInput.bank_title + '" for $'
              + args.depositInput.amount + ' deleted by ' + user.name
          }
        )
        await models.sales_deposit.destroy({
          where: {
            id: args.depositInput.id
          }
        })
        await updateCashInHand(sale)
        return true
      }
      return false
    },
    sales_food_delivery_entry: async (_, args, { auth }) => {
      const user = await models.user.findOne({
        where: {
          id: auth.userId
        }
      })
      if (!user) {
        return false
      }
      const sale = await models.sale.findOne({
        where: {
          id: args.deliveryInput.sale_id
        }
      })
      if (sale) {
        const id = args.deliveryInput.id || -1
        delete args.deliveryInput.id
        var delivery
        if (id >= 0) {
          delivery = await models.sales_food_delivery.findOne({
            where: {
              id: id
            }
          })
        }
        if (delivery) {
          delete args.deliveryInput.sale_id
          await models.sales_food_delivery.update(args.deliveryInput,
            {
              where: {
                id: id
              }
            }
          )
          await models.sales_log.create(
            {
              sale_id: sale.id,
              log: 'Delivery "' + args.deliveryInput.supplier_title + '" for $'
                + args.deliveryInput.amount + ' updated by ' + user.name
            }
          )
        }
        else {
          await models.sales_food_delivery.create(args.deliveryInput)
          await models.sales_log.create(
            {
              sale_id: sale.id,
              log: 'Delivery "' + args.deliveryInput.supplier_title + '" for $'
                + args.deliveryInput.amount + ' added by ' + user.name
            }
          )
        }
        await updateCashInHand(sale)
        return true
      }
      return false
    },
    sales_food_delivery_delete: async (_, args, { auth }) => {
      const user = await models.user.findOne({
        where: {
          id: auth.userId
        }
      })
      if (!user) {
        return false
      }
      const sale = await models.sale.findOne({
        where: {
          id: args.deliveryInput.sale_id
        }
      })
      if (sale) {
        await models.sales_log.create(
          {
            sale_id: sale.id,
            log: 'Delivery "' + args.deliveryInput.supplier_title + '" for $'
              + args.deliveryInput.amount + ' deleted by ' + user.name
          }
        )
        await models.sales_food_delivery.destroy({
          where: {
            id: args.deliveryInput.id
          }
        })
        await updateCashInHand(sale)
        return true
      }
      return false
    },
    sales_expense_entry: async (_, args, { auth }) => {
      const user = await models.user.findOne({
        where: {
          id: auth.userId
        }
      })
      if (!user) {
        return false
      }
      const sale = await models.sale.findOne({
        where: {
          id: args.expenseInput.sale_id
        }
      })
      if (!sale) {
        console.info("sale not found")
      }
      if (sale) {
        const id = args.expenseInput.id || -1
        delete args.expenseInput.id
        var expense
        if (id >= 0) {
          expense = await models.sales_expense.findOne({
            where: {
              id: id
            }
          })
        }
        if (expense) {
          await models.sales_expense.update(args.expenseInput,
            {
              where: {
                id: id
              }
            }
          )
          await models.sales_log.create(
            {
              sale_id: sale.id,
              log: 'Expense "' + args.expenseInput.expense_title + '" for $'
                + args.expenseInput.amount + ' updated by ' + user.name
            }
          )
        }
        else {
          console.info(args.expenseInput)
          await models.sales_expense.create(args.expenseInput)
          await models.sales_log.create(
            {
              sale_id: sale.id,
              log: 'Expense "' + args.expenseInput.expense_title + '" for $'
                + args.expenseInput.amount + ' added by ' + user.name
            }
          )
        }
        await updateCashInHand(sale)
        return true
      }
      return false
    },
    sales_expense_delete: async (_, args, { auth }) => {
      const user = await models.user.findOne({
        where: {
          id: auth.userId
        }
      })
      if (!user) {
        return false
      }
      const sale = await models.sale.findOne({
        where: {
          id: args.expenseInput.sale_id
        }
      })
      if (sale) {
        await models.sales_log.create(
          {
            sale_id: sale.id,
            log: 'Expense "' + args.expenseInput.expense_title + '" for $'
              + args.expenseInput.amount + ' deleted by ' + user.name
          }
        )
        await models.sales_expense.destroy({
          where: {
            id: args.expenseInput.id
          }
        })
        await updateCashInHand(sale)
        return true
      }
      return false
    },
    unit_entry: async (_, { unitInput }, { auth }) => {
      const user = await models.user.findByPk(auth.userId)
      if (!user) {
        return false
      }
      const id = unitInput.id || -1
      delete unitInput.id
      let unit
      if (id >= 0) {
        unit = await models.unit.findByPk(id)
      }
      if (unit) {
        await models.unit.update(unitInput,
          {
            where: {
              id: id
            }
          }
        )
        await models.unit_bank.destroy({
          where: {
            unit_id: id
          }
        })
        unitInput.bank_ids.forEach(async bankId => {
          await models.unit_bank.create({
            bank_id: bankId,
            unit_id: id
          })
        })
        await models.unit_franchise.upsert({
          franchise_id: unitInput.franchise_id,
          unit_id: id
        })
      }
      else {
        delete unitInput.id
        await models.unit.create(unitInput)
          .then(async result => {
            unitInput.bank_ids.forEach(async bankId => {
              await models.unit_bank.create({
                bank_id: bankId,
                unit_id: result.id
              })
            })
            await models.unit_franchise.upsert({
              franchise_id: unitInput.franchise_id,
              unit_id: result.id
            })
          })
      }
      return true
    },
    user_entry: async (_, { userInput }, { auth }) => {
      const loginUser = await models.user.findOne({
        where: {
          id: auth.userId
        }
      })
      if (!loginUser) {
        return false
      }
      delete userInput.id
      const existingUser = await models.user.findOne({
        where: {
          email: userInput.email
        }
      })
      if (existingUser) {
        await models.user.update(userInput,
          {
            where: {
              id: existingUser.id
            }
          }
        )
        await models.unit_user.destroy({
          where: {
            user_id: existingUser.id
          }
        })
        await userInput.unit_ids.forEach(async unitId => {
          await models.unit_user.create({
            user_id: existingUser.id,
            unit_id: unitId
          })
        })
        await models.user_access_flag.upsert({
          user_id: existingUser.id,
          access_flags: userInput.access_flags
        })
      }
      else {
        await models.user.create(userInput)
          .then(async result => {
            await userInput.unit_ids.forEach(async unitId => {
              await models.unit_user.create({
                user_id: result.id,
                unit_id: unitId
              })
            })
            await models.user_access_flag.create({
              user_id: result.id,
              access_flags: userInput.access_flags
            })
          })
      }
      return true
    },

    payroll_entry: async (_, { payrollInput }, { auth }) => {
      const user = await models.user.findOne({
        where: {
          id: auth.userId
        }
      })
      if (!user) {
        return -1
      }
      var payrollId = payrollInput.id || -1
      const employeePayrolls = payrollInput.employee_payrolls

      delete payrollInput.id
      delete payrollInput.employee_payrolls

      const existingPayroll = await models.payroll.findByPk(payrollId)
      if (existingPayroll) {
        await models.payroll.update(payrollInput, {
          where: {
            id: payrollId
          }
        })
      } else {
        await models.payroll.create(payrollInput)
          .then(async result => payrollId = result.id)
      }

      await employeePayrolls.forEach(async e => {
        const id = e.id || -1
        delete e.id
        if (id >= 0) {
          await models.employee_payroll.update(e, {
            where: {
              id: id
            }
          })
        }
        else {
          await models.employee_payroll.create(Object.assign(e, {
            payroll_id: payrollId
          })
          )
        }
      })

      return payrollId
    },

    payroll_set_status: async (_, { payroll_id, status }, { auth }) => {
      const user = await models.user.findOne({
        where: {
          id: auth.userId
        }
      })
      if (!user) {
        return false
      }
      models.payroll.update({
        status: status
      },
        {
          where: {
            id: payroll_id
          }
        })
      return true
    },
    sales_set_status: async (_, { salesId, status }, { auth }) => {
      const user = await models.user.findOne({
        where: {
          id: auth.userId
        }
      })
      if (!user) {
        console.log('failed ......')
        return false
      }
      await models.sale.update({
        status
      },
        {
          where: {
            id: salesId
          }
        })
      await models.sales_log.create(
        {
          sale_id: salesId,
          log: `Sales ${status ? 'finalized' : 'opened'} by ${user.name}`
        }
      )
      return true
    },

    // bank_entry: async (_, { bankInput }, { auth }) => {
    //   const user = await models.user.findOne({
    //     where: {
    //       id: auth.userId
    //     }
    //   })
    //   if (!user) {
    //     console.log('failed')
    //     return false
    //   }
    //   await models.bank.upsert(bankInput)
    //   return true
    // },
    // delete_bank: async (_, { id }, { auth }) => {
    //   const user = await models.user.findOne({ where: { id: auth.userId } })
    //   if (!user) return false

    //   await models.bank.destroy({ where: { id } })
    //   return true
    // },




    expense_entry: async (_, { expenseEntryInput }, { auth }) => {
      const user = await models.user.findOne({
        where: {
          id: auth.userId
        }
      })
      if (!user) {
        console.log('failed')
        return false
      }
      console.log(expenseEntryInput)
      await models.expense.upsert(expenseEntryInput)
      return true
    },
    job_title_entry: async (_, { jobTitleInput }, { auth }) => {
      const user = await models.user.findOne({
        where: {
          id: auth.userId
        }
      })
      if (!user) {
        console.log('failed')
        return false
      }
      await models.job_title.upsert(jobTitleInput)
      return true
    },
    supplier_entry: async (_, { supplierInput }, { auth }) => {
      const user = await models.user.findOne({
        where: {
          id: auth.userId
        }
      })
      if (!user) {
        console.log('failed')
        return false
      }
      await models.supplier.upsert(supplierInput)
      return true
    },
    franchise_entry: async (_, { franchiseInput }, { auth }) => {
      const user = await models.user.findOne({
        where: {
          id: auth.userId
        }
      })
      if (!user) {
        console.log('failed')
        return false
      }

      let franchise = null
      if (franchiseInput.id) {
        franchise = models.franchise.findByPk(franchiseInput.id)
      }
      let franchiseId = null
      if (franchise) {
        franchiseId = franchiseInput.id
        await models.franchise.update(franchiseInput, {
          where: {
            id: franchiseId
          }
        })
      } else {
        await models.franchise.create(franchiseInput).then(async result => franchiseId = result.id)
      }
      if (franchiseId) {
        models.franchise_supplier.destroy({
          where: {
            franchise_id: franchiseId
          }
        })
        franchiseInput.supplier_ids.forEach(async supplierId => {
          await models.franchise_supplier.create({
            supplier_id: supplierId,
            franchise_id: franchiseId
          })
        })
      }
      return true
    },
    payroll_delete: async (_, { payroll_id }, { auth }) => {
      const user = await models.user.findOne({
        where: {
          id: auth.userId
        }
      })
      if (!user) {
        console.log('failed')
        return false
      }
      await models.employee_payroll.destroy({ where: { payroll_id: payroll_id } })
      await models.payroll.destroy({ where: { id: payroll_id } })
      return true
    },
    fix_cash_in_hand: async (_, { unit_id }, { auth }) => {
      const user = await models.user.findOne({
        where: {
          id: 3 //auth.userId
        }
      })
      if (!user) {
        console.log('failed')
        return false
      }
      const sales = await models.sale.findAll({
        attributes: [
          'id',
          'cash',
          'cash_in_hand',
        ],
        where: {
          unit_id: unit_id
        }
      })
      for (let i = 0; i < sales.length; i++) {
        const sale = sales[i]
        const expenses = await models.sales_expense.findOne({
          attributes: [
            [sequelize.fn('SUM', sequelize.col('amount')), 'amount']
          ],
          where: {
            sale_id: sale.id
          }
        })

        const desopits = await models.sales_deposit.findOne({
          attributes: [
            [sequelize.fn('SUM', sequelize.col('amount')), 'amount']
          ],
          where: {
            sale_id: sale.id
          }
        })
        const totalExpenses = expenses.amount ? expenses.amount : 0.0
        const totalDeposits = desopits.amount ? desopits.amount : 0.0
        const cashInHand = sale.cash - totalExpenses - totalDeposits
        const diff = Math.abs(cashInHand - sale.cash_in_hand)

        if (diff > 0.1) {
          /*await models.sale.update(
            {
              cash_in_hand: cashInHand
            },
            {
              where: {
                id: sale.id
              }
            }
          )*/

          console.log(sale.id, cashInHand, sale.cash_in_hand, sale.cash, totalExpenses, totalDeposits)
        }
      }
      return true
    },
    file_archive_delete: async (_, { file_id }, { auth }) => {
      const user = await models.user.findOne({
        where: {
          id: auth.userId
        }
      })
      if (!user) {
        console.log('failed')
        return false
      }
      await models.file_archive.destroy({ where: { id: file_id } })
      return true
    },
    property_entry: async (_, { propertyInput }, context) => {
      return await savePropertyEntry(propertyInput, context);
    },
    save_received_revenue: async (_, { revenuereceiveInput }, context) => {
      return await saveReceivedRevenue(revenuereceiveInput, context);
    },

    bank_entry: async (_, { bankInput }, context) => {
      return await bankentry(bankInput, context);
    },

    update_property: async (_, { propertyUpdateInput }, context) => {
      return await updatePropertyEntry(propertyUpdateInput, context);
    },
    update_property_item: async (_, { propertyItemUpdateInput }, context) => {
      return await updatePropertyItemEntry(propertyItemUpdateInput, context);
    },

    update_property_tex: async (_, { propertyTaxUpdateInput }, context) => {
      return await updatePropertyTex(propertyTaxUpdateInput, context);
    },

    update_employee_shift: async (_, { employeeShiftInput }, context) => {
      return await updateEmployeeShift(employeeShiftInput, context);
    },

    set_default_shift: async (_, { id }, context) => {
      return await setEmployeeShiftDefault(id, context);
    },

    update_tenant_contacts: async (_, { contactsUpdateInput }, context) => {
      return await updateTenantContactsEntry(contactsUpdateInput, context);
    },
    update_tenant_occupancy: async (_, { occupancyUpdateInput }, context) => {
      return await updateTenantOccupancyEntry(occupancyUpdateInput, context);
    },
    update_tenant: async (_, { tenantUpdateInput }, context) => {
      console.log(tenantUpdateInput, "tenantUpdateInput")
      return await updateTenantEntry(tenantUpdateInput, context);
    },
    update_owner: async (_, { ownerUpdateInput }, context) => {
      console.log(ownerUpdateInput, "ownerUpdateInput")
      return await updateOwnerEntry(ownerUpdateInput, context);
    },
    update_bank: async (_, { bankUpdateInput }, context) => {
      console.log(bankUpdateInput, "bankUpdateInput")
      return await updateBankEntry(bankUpdateInput, context);
    },
    property_item_entry: async (_, { propertyItemInput }, context) => {
      return await savePropertyItemEntry(propertyItemInput, context);
    },
    property_tax_entry: async (_, { propertyTaxInput }, context) => {
      return await savePropertyTaxEntry(propertyTaxInput, context);
    },
    property_document_entry: async (_, { propertyDocInput }, context) => {
      return await savePropertyDocsEntry(propertyDocInput, context);
    },
    delete_property: async (_, { id }, context) => {
      return await deleteProperty(id, context);
    },
    delete_employee_shift: async (_, { id }, context) => {
      return await deleteEmployeeShift(id, context);
    },
    delete_ChartAccount: async (_, { id }, context) => {
      return await deleteChartAccount(id, context);
    },
    delete_consent: async (_, { id }, context) => {
      return await deleteConsent(id, context);
    },

    delete_task_swaps: async (_, { id }, context) => {
      return await delete_task_approved(id, context);
    },

    delete_service: async (_, { id }, context) => {
      return await deleteService(id, context);
    },

    delete_invoice: async (_, { id, type }, context) => {
      return await deleteInvoice(id, type, context);
    },
    delete_RecurringInvoice: async (_, { id }, context) => {
      return await deleteRecurringInvoice(id, context);
    },
    delete_Holiday: async (_, { id }, context) => {
      return await deleteHoliday(id, context);
    },
    delete_Department: async (_, { id }, context) => {
      return await deleteDepartment(id, context);
    },
    delete_Designations: async (_, { id }, context) => {
      return await deleteDesignations(id, context);
    },
    delete_leave: async (_, { id }, context) => {
      return await deleteleave(id, context);
    },
    delete_leave_app: async (_, { id }, context) => {
      return await deleteleaveapp(id, context);
    },
    delete_owner: async (_, { id }, context) => {
      return await deleteOwner(id, context);
    },
    delete_project: async (_, { id }, context) => {
      return await deleteproject(id, context);
    },
    delete_task: async (_, { id }, context) => {
      return await deletetask(id, context);
    },
    delete_subtask: async (_, { id }, context) => {
      return await deleteSubtask(id, context);
    },

    delete_client: async (_, { id }, context) => {
      return await deleteClient(id, context);
    },
    delete_client_service: async (_, { id }, context) => {
      return await deleteClientService(id, context);
    },
    delete_client_entity: async (_, { id }, context) => {
      return await deleteClientEntity(id, context);
    },
    delete_property_docs: async (_, { id }, context) => {
      return await deletePropertyDocs(id, context);
    },
    delete_property_tax: async (_, { id }, context) => {
      return await deletePropertyTaxes(id, context);
    },
    delete_tenant_contact: async (_, { id }, context) => {
      return await deleteTenantContacts(id, context);
    },
    delete_global_currency: async (_, { id }, context) => {
      return await deleteGlobalCurrency(id, context);
    },

    delete_package: async (_, { id }, context) => {
      return await deletepackage(id, context);
    },
    delete_vendor: async (_, { id }, context) => {
      return await deletevendor(id, context);
    },
    bank_delete: async (_, { id }, context) => {
      return await deletebank(id, context);
    },
    delete_temporary_employee: async (_, { id }, context) => {
      return await deleteTemoraryEmployee(id, context);
    },
    delete_vendorType: async (_, { id }, context) => {
      return await deleteVendorType(id, context);
    },

    delete_check: async (_, { id }, context) => {
      return await deleteCheck(id, context);
    },
    delete_expense_type: async (_, { id }, context) => {
      return await deleteExpenseType(id, context);
    },

    delete_expense: async (_, { id }, context) => {
      return await deleteExpense(id, context);
    },

    delete_invitation: async (_, { id }, context) => {
      return await deleteinvitation(id);
    },

    delete_tenant_occupancy: async (_, { id }, context) => {
      return await deleteTenantOccupancy(id, context);
    },
    delete_property_items: async (_, { id }, context) => {
      return await deletePropertyItems(id, context);
    },
    delete_property_taxes: async (_, { id }, context) => {
      return await deletepropertytaxes(id, context);
    },
    delete_property_taxes: async (_, { id }, context) => {
      return await deletepropertytaxes(id, context);
    },
    tenant_entry: async (_, { tenantInput }, context) => {
      return await saveTenantEntry(tenantInput, context);
    },
    invoice_entry: async (_, { invoiceInput }, context) => {
      return await saveInvoiceEntry(invoiceInput, context);
    },
    client_invoice_entry: async (_, { invoiceInput }, context) => {
      return await saveInvoiceEntry(invoiceInput, context);
    },
    create_employee_shift: async (_, { employeeShiftInput }, context) => {
      console.log(employeeShiftInput, "employeeShiftInput")
      return await saveEmployeeShiftEntry(employeeShiftInput, context);
    },
    save_shift_roster: async (_, { rosterInput }, context) => {
      console.log(rosterInput, "rosterInput")
      return await saveShiftRoster(rosterInput, context);
    },
    save_shift_roster_single: async (_, { rosterInputSingle }, context) => {
      console.log(rosterInputSingle, "rosterInputSingle")
      return await saveShiftRostersingle(rosterInputSingle, context);
    },
    save_invitation: async (_, { invitationInput }, context) => {
      console.log(invitationInput, "invitationInput")
      return await saveInvitation(invitationInput, context);
    },
    global_currency_entry: async (_, { currencyInput }, context) => {
      return await saveGlobalCurrency(currencyInput, context);
    },
    update_global_currency: async (_, { currencyUpdateInput }, context) => {
      return await updateGlobalCurrency(currencyUpdateInput, context);
    },
    markUpdateStatus: async (_, { markUpdatestatusInput }, context) => {
      return await markUpdateStatusHandle(markUpdatestatusInput, context);
    },
    update_shift_roster: async (_, { rosterupdateInput }, context) => {
      return await updateRosterEntry(rosterupdateInput, context);
    },
    invoice_entry_from_memorized: async (_, { invoiceInputFromMemorized }, context) => {
      return await saveInvoiceEntryFromMemorized(invoiceInputFromMemorized, context);
    },
    bulk_invoice_entry_from_memorized: async (_, { bulkInvoiceFromMemorizedInput }, context) => {
      const { invoices } = bulkInvoiceFromMemorizedInput;
      for (const payload of invoices) {
        await bulksaveInvoiceEntryFromMemorized(payload, context);
      }
      return true;
    },
    create_memorized_invoice: async (_, { memorizedInput }, context) => {
      return await saveMemorizedEntry(memorizedInput, context);
    },
    make_invoice_recurring_entry: async (_, { recurringInvoiceInput }, context) => {
      return await MakeRecurringInvoiceEntry(recurringInvoiceInput, context);
    },
    update_invoice: async (_, { invoiceUpdateInput }, context) => {
      return await updateInvoiceEntry(invoiceUpdateInput, context);
    },
    update_designation: async (_, { designationUpdateInput }, context) => {
      return await updatedesignation(designationUpdateInput, context);
    },
    update_department: async (_, { departmentUpdateInput }, context) => {
      return await updatedepartment(departmentUpdateInput, context);
    },
    update_recurringInvoice: async (_, { updateRecurringInvoiceInput }, context) => {
      return await updateRecuuringInvoiceEntry(updateRecurringInvoiceInput, context);
    },
    occupancy_entry: async (_, { occupancyInput }, context) => {
      return await saveOccupancyEntry(occupancyInput, context);
    },
    // contact_entry: async (_, { contactInput }, context) => {
    //   return await saveContactEntry(contactInput, context);
    // },
    rentalcontract_entry: async (_, { rentalcontractInput }, context) => {
      return await saveRentalcontractEntry(rentalcontractInput, context);
    },
    property_owner_entry: async (_, { owners }, context) => {
      return await savePropertyOwnerEntry(owners, context);
    },
    save_attendance: async (_, { attendanceInput }, context) => {
      return await saveAttendanceEntry(attendanceInput, context);
    },
    save_attendance_single_entry: async (_, { attendanceInputSingle }, context) => {
      return await saveAttendanceSingleEntry(attendanceInputSingle, context);
    },
    save_leave: async (_, { leaveInput }, context) => {
      return await saveleave(leaveInput, context);
    },
    save_leave_by_employee: async (_, { emp_leaveInput }, context) => {
      return await SaveLeaveEmployee(emp_leaveInput, context);
    },
    save_leave_by_emp_app: async (_, { emp_leaveInput }, context) => {
      return await saveLeaveEmpApp(emp_leaveInput, context);
    },


    save_leave_type: async (_, { leaveTypeInput }, context) => {
      return await saveleavetype(leaveTypeInput, context);
    },
    save_designation: async (_, { designationInput }, context) => {
      return await savedesignation(designationInput, context);
    },
    save_department: async (_, { departmentInput }, context) => {
      return await savedepartment(departmentInput, context);
    },
    save_holiday: async (_, { holidayInput }, context) => {
      return await saveholiday(holidayInput, context);
    },
    save_project: async (_, { projectInput }, context) => {
      return await saveproject(projectInput, context);
    },

    save_task: async (_, { taskInput }, context) => {
      return await savetask(taskInput, context);
    },



    save_consent: async (_, { consentInput }, context) => {
      return await saveConsent(consentInput, context);
    },

    update_consent: async (_, { consentUpdateInput }, context) => {
      return await updateConsent(consentUpdateInput, context);
    },

    save_package: async (_, { packageInput }, context) => {
      return await savepackage(packageInput, context);
    },

    client_entry: async (_, { clientInput }, context) => {
      return await saveclient(clientInput, context);
    },

    client_entity_entry: async (_, { entitiesInput }, context) => {
      return await saveClientEntity(entitiesInput, context);
    },

    update_client_entity: async (_, { entitiesUpdateInput }, context) => {
      return await updateClientEntity(entitiesUpdateInput, context);
    },

    update_client_service: async (_, { serviceUpdateInput }, context) => {
      return await updateClientService(serviceUpdateInput, context);
    },

    update_service: async (_, { serviceUpdateInput }, context) => {
      return await updateClientService(serviceUpdateInput, context);
    },

    save_service: async (_, { serviceInput }, context) => {
      return await saveServiceEntry(serviceInput, context);
    },

    save_employee_tasks: async (_, { employee_taskInput }, context) => {
      return await SaveEmployeeTasks(employee_taskInput, context);
    },

    save_task_history: async (_, { task_history_input }, context) => {
      return await SaveTaskHistory(task_history_input, context);
    },

    save_sub_task: async (_, { subTaskInput }, context) => {
      return await SaveSubTask(subTaskInput, context);
    },

    save_task_comment: async (_, { taskCommentInput }, context) => {
      return await SaveTaskComment(taskCommentInput, context);
    },

    save_task_note: async (_, { taskNoteInput }, context) => {
      return await SaveTaskNote(taskNoteInput, context);
    },

    react_to_comment: async (_, { reactToComment }, context) => {
      return await ReactToComment(reactToComment, context);
    },

    delete_comment_reaction: async (_, { comment_id, employee_id }, context) => {
      return await RemoveCommentReaction({ comment_id, employee_id }, context);
    },

    save_time_sheet: async (_, { timeSheetInput }, context) => {
      return await SaveTimeSheet(timeSheetInput, context);
    },

    update_time_sheet: async (_, { timeSheetInput }, context) => {
      return await UpdateTimeSheet(timeSheetInput, context);
    },

    save_vendor: async (_, { vendorInput }, context) => {
      return await saveVendor(vendorInput, context);
    },

    save_vendor_payment: async (_, { vendorPaymentInput }, context) => {
      return await saveVendorPayment(vendorPaymentInput, context);
    },

    update_vendor_payment: async (_, { vendorPaymentUpdateInput }, context) => {
      return await updateVendorPayment(vendorPaymentUpdateInput, context);
    },

    update_vendor_Tax: async (_, { vendorTaxUpdateInput }, context) => {
      return await updateVendorTax(vendorTaxUpdateInput, context);
    },

    update_ChartAccount: async (_, { chartAccountUpdateInput }, context) => {
      return await updateChartAccount(chartAccountUpdateInput, context);
    },

    update_expense_type: async (_, { expenseTypeupdateInput }, context) => {
      return await updateExpenseType(expenseTypeupdateInput, context);
    },

    update_expense: async (_, { expensesInput }, context) => {
      return await updateExpense(expensesInput, context);
    },

    save_vendorType: async (_, { vendorTypeInput }, context) => {
      return await saveVendorType(vendorTypeInput, context);
    },

    add_payment_term: async (_, { paymentTermInput }, context) => {
      return await addPaymentTerm(paymentTermInput, context);
    },

    save_chartAccount: async (_, { chartAccountInput }, context) => {
      return await saveChartAccount(chartAccountInput, context);
    },
    save_check: async (_, { checkpaymentinput }, context) => {
      return await savecheck(checkpaymentinput, context);
    },
    update_check: async (_, { checkpaymentUpdateInput }, context) => {
      return await updatecheck(checkpaymentUpdateInput, context); // ✅ return full object
    },
    update_package: async (_, { packageUpdateInput }, context) => {
      return await updatepackage(packageUpdateInput, context);
    },
    update_vendorType: async (_, { vendorTypeUpdateInput }, context) => {
      return await updateVendorType(vendorTypeUpdateInput, context);
    },
    update_vendor: async (_, { vendorUpdateInput }, context) => {
      return await updateVendor(vendorUpdateInput, context);
    },
    update_project: async (_, { projectUpdateInput }, context) => {
      return await updateProject(projectUpdateInput, context);
    },
    update_task: async (_, { taskUpdateInput }, context) => {
      return await updatetask(taskUpdateInput, context);
    },
    update_holiday: async (_, { holidayUpdateInput }, context) => {
      return await updateholiday(holidayUpdateInput, context);
    },
    update_leave: async (_, { leaveUpdateInput }, context) => {
      return await updateleave(leaveUpdateInput, context);
    },

    update_sub_task: async (_, { updatesubTaskInput }, context) => {
      return await UpdateSubTask(updatesubTaskInput, context);
    },

    update_leave_status: async (_, { updateLeaveStatusInput }, context) => {
      return await updateLeaveStatus(updateLeaveStatusInput, context);
    },

    update_sub_task_status: async (_, { updatesubTaskStatusInput }, context) => {
      return await UpdateSubTaskStatus(updatesubTaskStatusInput, context);
    },

    update_task_status: async (_, { updateTaskStatusInput }, context) => {
      return await UpdateTaskStatus(updateTaskStatusInput, context);
    },

    update_leave_by_employee_id: async (_, { emp_leaveUpdateInput }, context) => {
      return await updateLeaveEmployee(emp_leaveUpdateInput, context);
    },

    update_leave_by_employee_id_app: async (_, { empLeaveUpdate }, context) => {
      return await updateLeaveEmployeeApp(empLeaveUpdate, context);
    },

    update_client: async (_, { clientUpdateInput }, context) => {
      return await updateClient(clientUpdateInput, context);
    },
    update_Profile: async (_, { profileInput }, context) => {
      return await updateProfile(profileInput, context);
    },
    change_Password: async (_, { changePasswordInput }, context) => {
      return await changePassword(changePasswordInput, context);
    },
    reset_password: async (_, { resetPasswordInput }, context) => {
      return await resetPassword(resetPasswordInput, context);
    },
    check_email_exists: async (_, { emailInput }, context) => {
      return await checkEmailExists(emailInput, context);
    },
    refresh_token: async (_, { input }, context) => {
      return await refreshTokenHandle(input, context);
    },
    signUpUser: async (_, { input }, context) => {
      return await signUpUserByMobile(input, context);
    },
    registerWithMobile: async (_, { input }, context) => {
      return await RegisterWithMobileHandle(input, context);
    },
    completeRegistration: async (_, { input }, context) => {
      return await completeRegistrationHandle(input, context);
    },
    logUserActivity: async (_, { input }, context) => {
      return await logUserActivityHandle(input, context);
    },
    loginWithFace: async (_, { input }, context) => {
      return await loginWithFaceHandle(input, context);
    },
    loginWithEmail: async (_, { input }, context) => {
      return await loginWithEmailHandle(input, context);
    },
    logoutByApp: async (_, { input }, context) => {
      return await logoutHandle(input, context);
    },
    checkInWithFace: async (_, { input }, context) => {
      return await checkInWithFaceHandle(input, context);
    },
    checkOutWithFace: async (_, { input }, context) => {
      return await checkOutWithFaceHandle(input, context);
    },
    checkIn: async (_, { input }, context) => {
      return await checkInHandle(input, context);
    },
    checkOut: async (_, { input }, context) => {
      return await checkOutHandle(input, context);
    },
    save_expense_type: async (_, { expenseTypeInput }, context) => {
      return await saveExpensetype(expenseTypeInput, context);
    },
    save_expense: async (_, { expensesInput }, context) => {
      return await saveExpense(expensesInput, context);
    },
    swap_task: async (_, { swapInput }, context) => {
      return await swapTask(swapInput, context);
    },
    forward_task: async (_, { forwardInput }, context) => {
      return await forwardTask(forwardInput, context);
    },
    accept_consent: async (_, { acceptInput }, context) => {
      return await AcceptConsent(acceptInput, context);
    },
    accept_consent_bulk: async (_, { acceptInputbulk }, context) => {
      return await AcceptConsentBulk(acceptInputbulk, context);
    },
    save_income_type: async (_, { incomeTypeInput }, context) => {
      return await saveIncomeType(incomeTypeInput, context);
    },
    mark_approved_task_status: async (_, { markApprovedTaskStatusInput }, context) => {
      return await MarkApprovedTaskStatus(markApprovedTaskStatusInput, context);
    },
    mark_reject_task_status: async (_, { markRejectTaskStatusInput }, context) => {
      return await MarkRejectTaskStatus(markRejectTaskStatusInput, context);
    },
  },
  Leave: {
    date_range: (parent) => {
      if (!parent.date_range) return null;
      if (Array.isArray(parent.date_range)) return parent.date_range;

      try {
        return JSON.parse(parent.date_range); // stored as JSON string
      } catch {
        return String(parent.date_range)
          .split(',')
          .map(d => d.trim())
          .filter(Boolean);
      }
    }
  }
}

module.exports = resolvers
