<script setup lang="ts">
import { computed, nextTick, onMounted, ref } from 'vue'
import { getApiErrorMessage } from '@/services/api'
import { accountingService, type FinancialAccount } from '@/modules/accounting/services/accountingService'
import { inventoryService, type Product } from '@/modules/inventory/services/inventoryService'
import { posService, type PosSale, type PaginationMeta } from '@/modules/pos/services/posService'
import { useCompanyContextStore } from '@/stores/companyContext'

interface CartItem {
  product: Product
  quantity: number
  unit_price: number
  discount_amount: number
  tax_rate: number
}

const products = ref<Product[]>([])
const accounts = ref<FinancialAccount[]>([])
const sales = ref<PosSale[]>([])
const cart = ref<CartItem[]>([])
const selectedSale = ref<PosSale | null>(null)
const companyContext = useCompanyContextStore()
const loading = ref(false)
const saving = ref(false)
const error = ref('')
const success = ref('')
const currentCompanyId = ref(localStorage.getItem('current_company_id') || '')
const search = ref('')
const barcodeInput = ref('')
const paymentMethod = ref('cash')
const paymentAccountId = ref('')
const paidTotal = ref(0)
const lastSale = ref<PosSale | null>(null)
const saleFilters = ref({
  search: '',
  payment_method: '',
  payment_status: '',
  status: '',
  date_from: '',
  date_to: '',
})
const salePagination = ref<PaginationMeta>({
  current_page: 1,
  from: null,
  last_page: 1,
  per_page: 10,
  to: null,
  total: 0,
})

const filteredProducts = computed(() => {
  const term = search.value.trim().toLowerCase()

  if (!term) {
    return products.value
  }

  return products.value.filter((product) => {
    return product.name.toLowerCase().includes(term)
      || (product.sku || '').toLowerCase().includes(term)
      || (product.barcode || '').toLowerCase().includes(term)
  })
})

const subtotal = computed(() => {
  return cart.value.reduce((total, item) => total + (item.quantity * item.unit_price), 0)
})

const discountTotal = computed(() => {
  return cart.value.reduce((total, item) => total + Number(item.discount_amount || 0), 0)
})

const taxTotal = computed(() => {
  return cart.value.reduce((total, item) => {
    const taxable = Math.max((item.quantity * item.unit_price) - Number(item.discount_amount || 0), 0)

    return total + (taxable * (Number(item.tax_rate || 0) / 100))
  }, 0)
})

const total = computed(() => {
  return Math.max(subtotal.value - discountTotal.value + taxTotal.value, 0)
})

const changeTotal = computed(() => {
  return Math.max(Number(paidTotal.value || 0) - total.value, 0)
})
const canManagePos = computed(() => companyContext.hasPermission('pos.manage'))
const visibleSalesTotal = computed(() => sales.value.reduce((sum, sale) => sum + Number(sale.total || 0), 0))
const visiblePaidTotal = computed(() => sales.value.reduce((sum, sale) => sum + Number(sale.paid_total || 0), 0))
const visibleVoidedCount = computed(() => sales.value.filter((sale) => sale.status === 'voided').length)
const lowStockProductCount = computed(() => products.value.filter((product) => {
  return Number(product.current_stock || 0) <= Number(product.low_stock_threshold || 0)
}).length)

function money(value: number | string) {
  return Number(value || 0).toFixed(2)
}

function statusLabel(status: string) {
  return status
    .split('_')
    .map((part) => part.charAt(0).toUpperCase() + part.slice(1))
    .join(' ')
}

function statusClass(status: string) {
  return {
    off: ['voided', 'draft'].includes(status),
    warn: ['partial'].includes(status),
  }
}

function cartLineTotal(item: CartItem) {
  const subtotal = Number(item.quantity || 0) * Number(item.unit_price || 0)
  const taxable = Math.max(subtotal - Number(item.discount_amount || 0), 0)
  const tax = taxable * (Number(item.tax_rate || 0) / 100)

  return taxable + tax
}

function syncPaidTotal() {
  paidTotal.value = total.value
}

async function load() {
  if (!currentCompanyId.value) {
    error.value = 'Select a company workspace first.'
    return
  }

  loading.value = true
  error.value = ''

  try {
    const canUseAccounting = companyContext.hasFeature('accounting')
    const [productData, salePage, accountData] = await Promise.all([
      inventoryService.products(),
      posService.paginatedSales({
        search: saleFilters.value.search || undefined,
        payment_method: saleFilters.value.payment_method || undefined,
        payment_status: saleFilters.value.payment_status || undefined,
        status: saleFilters.value.status || undefined,
        date_from: saleFilters.value.date_from || undefined,
        date_to: saleFilters.value.date_to || undefined,
        page: salePagination.value.current_page,
        per_page: salePagination.value.per_page,
      }),
      canUseAccounting ? accountingService.accounts() : Promise.resolve([]),
    ])
    products.value = productData.filter((product) => product.status === 'active')
    sales.value = salePage.data
    salePagination.value = salePage.meta
    accounts.value = accountData
  } catch (loadError) {
    error.value = getApiErrorMessage(loadError, 'Unable to load POS data.')
  } finally {
    loading.value = false
  }
}

async function loadSalePage(page: number) {
  salePagination.value.current_page = Math.min(Math.max(page, 1), salePagination.value.last_page || 1)
  await load()
}

async function applySaleFilters() {
  if (saleFilters.value.date_from && saleFilters.value.date_to && saleFilters.value.date_from > saleFilters.value.date_to) {
    error.value = 'From date must be before To date.'
    return
  }

  salePagination.value.current_page = 1
  await load()
}

async function resetSaleFilters() {
  saleFilters.value = {
    search: '',
    payment_method: '',
    payment_status: '',
    status: '',
    date_from: '',
    date_to: '',
  }
  salePagination.value.current_page = 1
  await load()
}

function addToCart(product: Product) {
  const stock = Number(product.current_stock)
  error.value = ''
  success.value = ''

  if (stock <= 0) {
    error.value = 'This product is out of stock.'
    return
  }

  const existing = cart.value.find((item) => item.product.id === product.id)

  if (existing) {
    if (existing.quantity + 1 > stock) {
      error.value = 'Not enough stock for this product.'
      return
    }

    existing.quantity += 1
    syncPaidTotal()
    return
  }

  cart.value.push({
    product,
    quantity: 1,
    unit_price: Number(product.selling_price || 0),
    discount_amount: 0,
    tax_rate: 0,
  })
  paidTotal.value = total.value
}

async function scanBarcode() {
  const code = barcodeInput.value.trim()

  if (!code) {
    return
  }

  error.value = ''
  success.value = ''

  try {
    const product = await inventoryService.lookupProduct(code)
    const cachedProduct = products.value.find((item) => item.id === product.id)

    if (!cachedProduct) {
      products.value = [product, ...products.value]
    } else {
      products.value = products.value.map((item) => item.id === product.id ? product : item)
    }

    addToCart(product)
    barcodeInput.value = ''

    if (!error.value) {
      success.value = `${product.name} added from scan.`
    }
  } catch (scanError) {
    error.value = getApiErrorMessage(scanError, 'No active product found for this barcode or SKU.')
  }
}

function removeFromCart(productId: number) {
  cart.value = cart.value.filter((item) => item.product.id !== productId)
  syncPaidTotal()
}

function setQuantity(item: CartItem, value: number) {
  const stock = Number(item.product.current_stock)
  const next = Math.max(Number(value || 1), 1)
  item.quantity = Math.min(next, stock)
  syncPaidTotal()
}

async function completeSale() {
  if (cart.value.length === 0) {
    error.value = 'Add at least one product to cart.'
    return
  }

  if (Number(paidTotal.value || 0) < total.value) {
    error.value = 'Paid amount cannot be less than sale total.'
    return
  }

  saving.value = true
  error.value = ''
  success.value = ''

  try {
    const sale = await posService.createSale({
      financial_account_id: paymentAccountId.value ? Number(paymentAccountId.value) : undefined,
      sale_date: new Date().toISOString().slice(0, 10),
      payment_method: paymentMethod.value,
      paid_total: Number(paidTotal.value || total.value),
      items: cart.value.map((item) => ({
        product_id: item.product.id,
        quantity: Number(item.quantity),
        unit_price: Number(item.unit_price),
        discount_amount: Number(item.discount_amount || 0),
        tax_rate: Number(item.tax_rate || 0),
      })),
    })
    lastSale.value = sale
    selectedSale.value = sale
    cart.value = []
    paidTotal.value = 0
    salePagination.value.current_page = 1
    await load()
    success.value = `${sale.sale_number} completed. Change BDT ${sale.change_total}.`
  } catch (saleError) {
    error.value = getApiErrorMessage(saleError, 'Unable to complete sale.')
  } finally {
    saving.value = false
  }
}

async function openSale(sale: PosSale) {
  error.value = ''

  try {
    selectedSale.value = await posService.sale(sale)
  } catch (openSaleError) {
    error.value = getApiErrorMessage(openSaleError, 'Unable to load receipt.')
  }
}

async function voidSale(sale: PosSale) {
  saving.value = true
  error.value = ''
  success.value = ''

  try {
    const updatedSale = await posService.updateSale(sale, { status: 'voided' })
    sales.value = sales.value.map((item) => item.id === updatedSale.id ? updatedSale : item)
    if (selectedSale.value?.id === updatedSale.id) {
      selectedSale.value = updatedSale
    }
    await load()
    success.value = `${updatedSale.sale_number} voided.`
  } catch (voidError) {
    error.value = getApiErrorMessage(voidError, 'Unable to void sale.')
  } finally {
    saving.value = false
  }
}

async function printSale(sale: PosSale) {
  await openSale(sale)
  await nextTick()
  window.print()
}

async function exportSale(sale: PosSale) {
  error.value = ''

  try {
    const html = await posService.exportSaleHtml(sale)
    const url = URL.createObjectURL(html)
    window.open(url, '_blank', 'noopener,noreferrer')
    window.setTimeout(() => URL.revokeObjectURL(url), 60_000)
  } catch (exportError) {
    error.value = getApiErrorMessage(exportError, 'Unable to export receipt.')
  }
}

async function printSelectedSale() {
  await nextTick()
  window.print()
}

onMounted(async () => {
  await companyContext.loadCurrent()
  await load()
})
</script>

<template>
  <section class="stack">
    <article class="panel no-print">
      <h2>POS</h2>
      <p v-if="loading">Loading POS...</p>
      <p v-if="error" class="error">{{ error }}</p>
      <p v-if="success" class="success">{{ success }}</p>
      <p v-if="lastSale" class="muted">Last sale {{ lastSale.sale_number }} completed. Change BDT {{ lastSale.change_total }}.</p>
    </article>

    <section class="grid compact-grid no-print">
      <article class="metric">
        <span>Products Ready</span>
        <strong>{{ products.length }}</strong>
        <small>{{ lowStockProductCount }} low stock</small>
      </article>
      <article class="metric">
        <span>Current Cart</span>
        <strong>BDT {{ money(total) }}</strong>
        <small>{{ cart.length }} line item(s)</small>
      </article>
      <article class="metric">
        <span>Visible Sales</span>
        <strong>BDT {{ money(visibleSalesTotal) }}</strong>
        <small>{{ sales.length }} sales on page</small>
      </article>
      <article class="metric">
        <span>Paid</span>
        <strong>BDT {{ money(visiblePaidTotal) }}</strong>
        <small>{{ visibleVoidedCount }} voided on page</small>
      </article>
    </section>

    <section class="grid wide-grid no-print">
      <article class="panel stack">
        <form class="form" @submit.prevent="scanBarcode">
          <div class="field">
            <label for="barcode_scan">Barcode Scanner</label>
            <input
              id="barcode_scan"
              v-model="barcodeInput"
              autocomplete="off"
              inputmode="text"
              type="text"
              placeholder="Scan barcode or SKU, then Enter"
              :disabled="loading || saving || !canManagePos"
            />
          </div>
          <button class="button primary" type="submit" :disabled="loading || saving || !barcodeInput.trim() || !canManagePos">
            Add Scanned Item
          </button>
        </form>

        <div class="field">
          <label for="product_search">Product Search</label>
          <input id="product_search" v-model="search" type="search" placeholder="Name, SKU, or barcode" />
        </div>

        <div class="stack">
          <div v-for="product in filteredProducts" :key="product.id" class="list-item">
            <div>
              <strong>{{ product.name }}</strong>
              <span>{{ product.sku || 'No SKU' }} - Stock {{ product.current_stock }} {{ product.unit }}</span>
              <span v-if="product.barcode">Barcode {{ product.barcode }}</span>
            </div>
            <div class="inline-actions">
              <span
                v-if="Number(product.current_stock || 0) <= Number(product.low_stock_threshold || 0)"
                class="status-pill warn"
              >
                Low
              </span>
              <span>BDT {{ product.selling_price }}</span>
              <button
                v-if="canManagePos"
                class="button ghost"
                type="button"
                :disabled="Number(product.current_stock) <= 0"
                @click="addToCart(product)"
              >
                Add
              </button>
            </div>
          </div>
          <p v-if="filteredProducts.length === 0 && !loading">No products found.</p>
        </div>
      </article>

      <article v-if="canManagePos" class="panel stack">
        <h2>Cart</h2>

        <div class="stack">
          <div v-for="item in cart" :key="item.product.id" class="list-item">
            <div>
              <strong>{{ item.product.name }}</strong>
              <span>{{ item.product.sku || item.product.barcode || 'No SKU/barcode' }} - Stock {{ item.product.current_stock }}</span>
              <span>Line total BDT {{ money(cartLineTotal(item)) }}</span>
            </div>
            <div class="grid compact-grid" style="min-width: 360px">
              <div class="field">
                <label :for="`cart_qty_${item.product.id}`">Qty</label>
                <input
                  :id="`cart_qty_${item.product.id}`"
                  v-model.number="item.quantity"
                  min="1"
                  :max="Number(item.product.current_stock)"
                  step="1"
                  type="number"
                  @change="setQuantity(item, item.quantity)"
                />
              </div>
              <div class="field">
                <label :for="`cart_price_${item.product.id}`">Price</label>
                <input :id="`cart_price_${item.product.id}`" v-model.number="item.unit_price" min="0" step="0.01" type="number" @change="syncPaidTotal" />
              </div>
              <div class="field">
                <label :for="`cart_discount_${item.product.id}`">Discount</label>
                <input :id="`cart_discount_${item.product.id}`" v-model.number="item.discount_amount" min="0" step="0.01" type="number" @change="syncPaidTotal" />
              </div>
              <div class="field">
                <label :for="`cart_tax_${item.product.id}`">Tax %</label>
                <input :id="`cart_tax_${item.product.id}`" v-model.number="item.tax_rate" min="0" step="0.01" type="number" @change="syncPaidTotal" />
              </div>
              <button class="button ghost" type="button" @click="removeFromCart(item.product.id)">Remove</button>
            </div>
          </div>
          <p v-if="cart.length === 0">Cart is empty.</p>
        </div>

        <div class="grid compact-grid">
          <div class="metric">
            <span>Subtotal</span>
            <strong>BDT {{ money(subtotal) }}</strong>
          </div>
          <div class="metric">
            <span>Discount</span>
            <strong>BDT {{ money(discountTotal) }}</strong>
          </div>
          <div class="metric">
            <span>Tax</span>
            <strong>BDT {{ money(taxTotal) }}</strong>
          </div>
          <div class="metric">
            <span>Total</span>
            <strong>BDT {{ money(total) }}</strong>
          </div>
        </div>

        <div class="grid compact-grid">
          <div class="field">
            <label for="payment_method">Payment</label>
            <select id="payment_method" v-model="paymentMethod">
              <option value="cash">Cash</option>
              <option value="card">Card</option>
              <option value="mobile_bank_transfer">Mobile Banking</option>
              <option value="bank_transfer">Bank Transfer</option>
            </select>
          </div>
          <div v-if="accounts.length > 0" class="field">
            <label for="payment_account">Paid Into</label>
            <select id="payment_account" v-model="paymentAccountId">
              <option value="">No ledger account</option>
              <option v-for="account in accounts" :key="account.id" :value="String(account.id)">
                {{ account.name }} - BDT {{ account.current_balance }}
              </option>
            </select>
          </div>
          <div class="field">
            <label for="paid_total">Paid</label>
            <input id="paid_total" v-model.number="paidTotal" min="0" step="0.01" type="number" />
          </div>
          <div class="metric">
            <span>Change</span>
            <strong>BDT {{ money(changeTotal) }}</strong>
          </div>
        </div>

        <button class="button primary" type="button" :disabled="saving || cart.length === 0 || !currentCompanyId" @click="completeSale">
          {{ saving ? 'Completing...' : 'Complete Sale' }}
        </button>
      </article>
    </section>

    <article class="panel no-print">
      <h2>Recent Sales</h2>
      <form class="form" @submit.prevent="applySaleFilters">
        <div class="grid compact-grid">
          <div class="field">
            <label for="sale_search">Search</label>
            <input id="sale_search" v-model="saleFilters.search" type="search" placeholder="Receipt or payment" />
          </div>
          <div class="field">
            <label for="sale_payment_method">Payment</label>
            <select id="sale_payment_method" v-model="saleFilters.payment_method">
              <option value="">All</option>
              <option value="cash">Cash</option>
              <option value="card">Card</option>
              <option value="mobile_bank_transfer">Mobile Banking</option>
              <option value="bank_transfer">Bank Transfer</option>
            </select>
          </div>
          <div class="field">
            <label for="sale_payment_status">Status</label>
            <select id="sale_payment_status" v-model="saleFilters.payment_status">
              <option value="">All</option>
              <option value="paid">Paid</option>
              <option value="partial">Partial</option>
              <option value="voided">Voided</option>
            </select>
          </div>
          <div class="field">
            <label for="sale_status">Sale</label>
            <select id="sale_status" v-model="saleFilters.status">
              <option value="">All</option>
              <option value="completed">Completed</option>
              <option value="voided">Voided</option>
            </select>
          </div>
          <div class="field">
            <label for="sale_date_from">From</label>
            <input id="sale_date_from" v-model="saleFilters.date_from" type="date" />
          </div>
          <div class="field">
            <label for="sale_date_to">To</label>
            <input id="sale_date_to" v-model="saleFilters.date_to" type="date" />
          </div>
          <div class="field">
            <label for="sale_per_page">Per Page</label>
            <select id="sale_per_page" v-model.number="salePagination.per_page">
              <option :value="10">10</option>
              <option :value="25">25</option>
              <option :value="50">50</option>
            </select>
          </div>
        </div>
        <div class="inline-actions">
          <button class="button primary" type="submit">Apply Filters</button>
          <button class="button ghost" type="button" @click="resetSaleFilters">Reset</button>
        </div>
      </form>
      <div class="stack">
        <div v-for="sale in sales" :key="sale.id" class="list-item">
          <div>
            <strong>{{ sale.sale_number }}</strong>
            <span>{{ sale.sale_date }} - {{ statusLabel(sale.payment_method) }}</span>
          </div>
          <div class="inline-actions">
            <span class="status-pill" :class="statusClass(sale.payment_status)">{{ statusLabel(sale.payment_status) }}</span>
            <span class="status-pill" :class="statusClass(sale.status)">{{ statusLabel(sale.status) }}</span>
            <span>BDT {{ sale.total }}</span>
            <button v-if="canManagePos && sale.status !== 'voided'" class="button ghost" type="button" :disabled="saving" @click="voidSale(sale)">
              Void
            </button>
            <button class="button ghost" type="button" @click="openSale(sale)">Preview</button>
            <button class="button ghost" type="button" @click="exportSale(sale)">Export</button>
            <button class="button primary" type="button" @click="printSale(sale)">Print</button>
          </div>
        </div>
        <p v-if="sales.length === 0 && !loading">No sales yet.</p>
      </div>
      <div class="inline-actions">
        <span>
          Showing {{ salePagination.from || 0 }}-{{ salePagination.to || 0 }} of {{ salePagination.total }}
        </span>
        <button
          class="button ghost"
          type="button"
          :disabled="loading || salePagination.current_page <= 1"
          @click="loadSalePage(salePagination.current_page - 1)"
        >
          Previous
        </button>
        <span>Page {{ salePagination.current_page }} of {{ salePagination.last_page }}</span>
        <button
          class="button ghost"
          type="button"
          :disabled="loading || salePagination.current_page >= salePagination.last_page"
          @click="loadSalePage(salePagination.current_page + 1)"
        >
          Next
        </button>
      </div>
    </article>

    <article v-if="selectedSale" class="panel print-document receipt-document">
      <div class="print-header receipt-header">
        <div>
          <h2>{{ companyContext.company?.name || 'BizNovia' }}</h2>
          <p>{{ companyContext.company?.address || 'Business address' }}</p>
          <p>{{ companyContext.company?.phone || '' }}</p>
        </div>
      </div>

      <div class="receipt-meta">
        <strong>Receipt {{ selectedSale.sale_number }}</strong>
        <span>{{ selectedSale.sale_date }} - {{ statusLabel(selectedSale.payment_method) }}</span>
        <span class="status-pill" :class="statusClass(selectedSale.status)">{{ statusLabel(selectedSale.status) }}</span>
      </div>

      <table class="print-table">
        <thead>
          <tr>
            <th>Item</th>
            <th>Qty</th>
            <th>Price</th>
            <th>Total</th>
          </tr>
        </thead>
        <tbody>
          <tr v-for="item in selectedSale.items" :key="item.id">
            <td>{{ item.description }}</td>
            <td>{{ item.quantity }}</td>
            <td>BDT {{ item.unit_price }}</td>
            <td>BDT {{ item.line_total }}</td>
          </tr>
        </tbody>
      </table>

      <section class="print-totals">
        <div><span>Subtotal</span><strong>BDT {{ selectedSale.subtotal }}</strong></div>
        <div><span>Discount</span><strong>BDT {{ selectedSale.discount_total }}</strong></div>
        <div><span>Tax</span><strong>BDT {{ selectedSale.tax_total }}</strong></div>
        <div><span>Total</span><strong>BDT {{ selectedSale.total }}</strong></div>
        <div><span>Paid</span><strong>BDT {{ selectedSale.paid_total }}</strong></div>
        <div><span>Change</span><strong>BDT {{ selectedSale.change_total }}</strong></div>
      </section>

      <p class="receipt-footer">Thank you for your purchase.</p>

      <div class="inline-actions no-print">
        <button class="button primary" type="button" @click="printSelectedSale">Print Receipt</button>
        <button class="button ghost" type="button" @click="exportSale(selectedSale)">Export</button>
        <button class="button ghost" type="button" @click="selectedSale = null">Close</button>
      </div>
    </article>
  </section>
</template>
