import { Card, message, Table, Typography } from 'antd'
import React, { useMemo } from 'react'

import { FormsPrice } from 'apiClient/api/interface'
import { FormsTaxRate } from 'apiClient/services/billing/interface'
import CurrencyValue, { formatCurrencyValue } from 'components/currency/Value'

interface CostItem {
  name: string
  cost_price: string
}

interface CopyRow {
  name: string
  formattedCostPrice: string
}

const isZeroCostPrice = (costPrice: string) => {
  const normalizedCostPrice = costPrice.trim()

  return /^0(?:\.0+)?$/.test(normalizedCostPrice)
}

const escapeHtml = (value: string) =>
  value
    .replace(/&/g, '&amp;')
    .replace(/</g, '&lt;')
    .replace(/>/g, '&gt;')
    .replace(/"/g, '&quot;')
    .replace(/'/g, '&#39;')

const getBillCostsCopyRows = (categoryUnitCosts?: {
  [key: string]: FormsPrice
}) => {
  if (!categoryUnitCosts) {
    return []
  }

  return Object.keys(categoryUnitCosts)
    .map((key) => ({
      name: key,
      formattedCostPrice: `${formatCurrencyValue(
        categoryUnitCosts[key].cost_price,
        false
      )}`
    }))
    .filter(({ formattedCostPrice }) => !isZeroCostPrice(formattedCostPrice))
}

const formatBillCostsCopyText = (categoryUnitCosts?: {
  [key: string]: FormsPrice
}) => {
  const copyRows = getBillCostsCopyRows(categoryUnitCosts)

  if (!copyRows.length) {
    return ''
  }

  return copyRows
    .map(({ name, formattedCostPrice }) => `${name}\t${formattedCostPrice}`)
    .join('\r\n')
}

const formatBillCostsCopyHtml = (copyRows: CopyRow[]) => {
  if (!copyRows.length) {
    return ''
  }

  const rows = copyRows
    .map(
      ({ name, formattedCostPrice }) =>
        `<tr><td>${escapeHtml(name)}</td><td>${escapeHtml(
          formattedCostPrice
        )}</td></tr>`
    )
    .join('')

  return `<table><tbody>${rows}</tbody></table>`
}

export default function BillCosts({
  category_unit_costs,
  tax_rate,
  withTaxRate
}: {
  category_unit_costs: { [key: string]: FormsPrice }
  tax_rate?: FormsTaxRate
  withTaxRate?: boolean
}) {
  const columns = useMemo(
    () => [
      {
        title: 'Category Name',
        dataIndex: 'name'
      },
      {
        title: 'Cost Price',
        dataIndex: 'cost_price',
        render: (text: any, record: CostItem) => {
          return <CurrencyValue isCent={false} value={record.cost_price} />
        }
      }
    ],
    []
  )

  const dataSource = category_unit_costs
    ? Object.keys(category_unit_costs).map((key) => ({
        name: key,
        cost_price: category_unit_costs[key].cost_price
      }))
    : []

  const copyText = useMemo(
    () => formatBillCostsCopyText(category_unit_costs),
    [category_unit_costs]
  )

  const copyRows = useMemo(
    () => getBillCostsCopyRows(category_unit_costs),
    [category_unit_costs]
  )

  const handleCopy = async () => {
    if (!copyRows.length) {
      message.info('No data to copy')
      return
    }

    try {
      if (navigator.clipboard.write && typeof ClipboardItem !== 'undefined') {
        const copyHtml = formatBillCostsCopyHtml(copyRows)

        await navigator.clipboard.write([
          new ClipboardItem({
            'text/plain': new Blob([copyText], { type: 'text/plain' }),
            'text/html': new Blob([copyHtml], { type: 'text/html' })
          })
        ])
      } else {
        await navigator.clipboard.writeText(copyText)
      }

      message.success('Copied')
    } catch (error) {
      message.error('Copy failed')
    }
  }

  return (
    <Card
      extra={
        <Typography.Link onClick={() => void handleCopy()}>
          Copy data
        </Typography.Link>
      }
    >
      {withTaxRate && (
        <p>
          <b>Tax rate: </b>
          <Typography.Text type={tax_rate ? 'success' : 'warning'}>
            {tax_rate?.rate !== undefined && tax_rate?.rate !== null
              ? tax_rate.display_name + '(' + tax_rate.rate + '%)'
              : 'Not Set'}
          </Typography.Text>
        </p>
      )}
      <Table
        dataSource={dataSource}
        columns={columns}
        rowKey="name"
        size="small"
      />
    </Card>
  )
}
