import {
  Autocomplete,
  Typography,
  Sheet,
  Table,
  Grid,
  Input,
  Button,
  Box,
  Theme,
  FormControl,
  FormLabel,
} from "@mui/joy";
import { api } from "~/utils/api";
import { useState } from "react";

import * as Icon from "react-feather";
import TopSection from "~/components/TopSection";

import { Product } from "@prisma/client";
import { prisma } from "~/server/db";
import { GetServerSidePropsContext } from "next";
import CustomAlert from "~/components/CustomAlert";

const sheetSx = {
  width: "100%",
  borderRadius: "md",
  flex: 1,
  overflow: "auto",
  minHeight: 0,
};

const tableSx = {
  "--TableCell-headBackground": (theme: Theme) =>
    theme.vars.palette.background.level1,
  "--Table-headerUnderlineThickness": "1px",
  "--TableRow-hoverBackground": (theme: Theme) =>
    theme.vars.palette.background.level1,
};

type SalePayment = { id: number; name: string; value: number | string };
type SaleProduct = Product & {
  quantity: number;
};
type TotalPaid = [number, number];
type PurchaseTotal = [number, number];

function getPurchaseTotal(products: SaleProduct[], discount: number) {
  let totalWithoutDiscount = 0;
  products.forEach(
    (product) => (totalWithoutDiscount += product.quantity * product.price)
  );

  let totalWithDiscount = totalWithoutDiscount;
  if (discount > 0) {
    totalWithDiscount =
      totalWithoutDiscount - (totalWithoutDiscount * discount) / 100;
  }
  return [totalWithDiscount, totalWithoutDiscount];
}

function getTotalPaid(
  payments: SalePayment[],
  purchaseTotal: number
): TotalPaid {
  let totalPaid = 0;

  for (const payment of payments) {
    let fixedValue = 0;
    if (typeof payment.value === "number") fixedValue = payment.value;
    totalPaid += fixedValue;
  }
  const remainder = purchaseTotal - totalPaid;
  return [totalPaid, remainder];
}

export async function getServerSideProps(ctx: GetServerSidePropsContext) {
  const paymentMethods = await prisma.paymentMethod.findMany();
  const salePayments: SalePayment[] = paymentMethods.map((paymentMethod) => {
    return { id: paymentMethod.id, name: paymentMethod.name, value: 0 };
  });
  return {
    props: {
      salePayments,
    },
  };
}

export default function Index({ salePayments }) {
  const [products, setProducts] = useState<SaleProduct[]>([]);
  const productsQuery = api.product.getProducts.useQuery(undefined, {
    refetchOnWindowFocus: false,
  });

  const [customAlert, setAlert] = useState({
    open: false,
    type: "success",
    text: "",
    duration: 6000,
  });

  const [loading, setLoading] = useState(false);

  const [payments, setPayments] = useState<SalePayment[]>(salePayments);

  const [discount, setDiscount] = useState(0);

  const [totalWithDiscount, totalWithoutDiscount]: PurchaseTotal =
    getPurchaseTotal(products, discount);

  const [totalPaid, remainder]: TotalPaid = getTotalPaid(
    payments,
    totalWithDiscount
  );

  const handlePaymentChange = (idx: number, value: number | string) => {
    const salePayment = payments[idx];
    if (salePayment !== undefined) {
      const updatedSalePayment = { ...salePayment, value };
      setPayments((prevPayments) => {
        const newPayments = [...prevPayments];
        newPayments[idx] = updatedSalePayment;
        return newPayments;
      });
    }
  };

  const addProduct = (product: Product) => {
    const selectedProduct: SaleProduct = {
      ...product,
      quantity: 1,
    };
    setProducts([...products, selectedProduct]);
  };

  const updateProductQuantity = (idx: number, quantity: number) => {
    const selectedProduct = products[idx];
    if (selectedProduct !== undefined) {
      const updatedProduct: SaleProduct = { ...selectedProduct, quantity };
      setProducts([
        ...products.slice(0, idx),
        updatedProduct,
        ...products.slice(idx + 1),
      ]);
    }
  };

  const openAlert = (settings) => {
    setAlert({ ...settings, duration: 6000, open: true });
  };

  const createSaleMutation = api.sale.createSale.useMutation({
    onSuccess: (data) => {
      openAlert({
        type: "success",
        text: "Venda finalizada com sucesso!",
      });
      resetPage();
    },
    onError: (error) => {
      openAlert({
        type: "warning",
        text: error.message,
      });
    },
    onSettled: () => setLoading(false),
  });

  const resetPage = () => {
    setProducts([]);
    setPayments(
      payments.map((payment) => {
        return {
          ...payment,
          value: 0,
        };
      })
    );
  };

  const createSale = () => {
    setLoading(true);
    if (products.length === 0) {
      openAlert({
        type: "warning",
        text: "Nenhum produto lançado!",
      });
      setLoading(false);
      return;
    }
    createSaleMutation.mutate({
      discount_percent: discount > 0 ? discount : null,
      total_sale: totalWithoutDiscount,
      total_discount: discount > 0 ? totalWithDiscount : null,
      total_paid: totalPaid,
      sale_payments: payments.map((payment) => {
        let fixedValue = 0;
        if (typeof payment.value === "number") fixedValue = payment.value;
        return {
          payment_method_id: payment.id,
          value: fixedValue,
        };
      }),
      sale_items: products.map((product) => {
        return {
          product_id: product.id,
          quantity: product.quantity,
          price: product.price,
        };
      }),
    });
  };

  const [barcode, setBarcode] = useState("");

  return (
    <>
      <TopSection pageName={"Balcão"} topSectionButton={""} />
      <CustomAlert customAlert={customAlert} setAlert={setAlert} />
      <Grid container>
        <Grid xs={8}>
          <Grid container justifyContent='space-around' spacing={2}>
            <Grid xs={3}>
              <FormControl>
                <FormLabel>Cod. Barras</FormLabel>
                <Input
                  autoFocus
                  value={barcode}
                  onChange={(e) => {
                    setBarcode(e.target.value);
                    if (e.target.value.length === 13) {
                      const barcode: string = e.target.value;
                      if (productsQuery.isSuccess) {
                        const productIdx =
                          productsQuery.data.products.findIndex(
                            (product) => product.barcode === barcode
                          );
                        if (productIdx > -1) {
                          const isCurrentlySelected = products.findIndex(
                            (product) => product.barcode === barcode
                          );
                          if (isCurrentlySelected === -1) {
                            const product =
                              productsQuery.data.products[productIdx];
                            if (product !== undefined) {
                              addProduct(product);
                            }
                          }
                        } else {
                          alert("Produto não encontrado!");
                        }
                      }
                      setBarcode("");
                    }
                  }}
                />
              </FormControl>
            </Grid>
            <Grid xs={9}>
              <FormControl>
                <FormLabel>Produtos</FormLabel>
                <Autocomplete
                  options={productsQuery.data?.products ?? []}
                  isOptionEqualToValue={(option, value) =>
                    option.id === value.id
                  }
                  getOptionLabel={(item) =>
                    `${item.name} - ${item.price.toLocaleString("pt-BR", {
                      style: "currency",
                      currency: "BRL",
                    })}`
                  }
                  onChange={(_, item, reason) => {
                    if (reason === "clear") {
                      return;
                    }
                    if (
                      products.findIndex((product) => product.id === item?.id) >
                      -1
                    )
                      return;
                    if (item !== null) {
                      addProduct(item);
                    }
                  }}
                />
              </FormControl>
            </Grid>
          </Grid>
          <Grid mt={3} xs={12}>
            {" "}
            <Sheet
              className='OrderTableContainer'
              variant='outlined'
              sx={sheetSx}
            >
              <Table
                aria-labelledby='tableTitle'
                stickyHeader
                hoverRow
                sx={tableSx}
              >
                <thead>
                  <tr>
                    <th style={{ width: 120, padding: 12 }}>Codigo</th>
                    <th style={{ width: 120, padding: 12 }}>Nome</th>
                    <th style={{ width: 120, padding: 12 }}>Preço (R$)</th>
                    <th style={{ width: 100, padding: 12 }}>Quantidade</th>
                    <th style={{ width: 120, padding: 12 }}>Sub-total</th>
                    <th style={{ width: 70, padding: 12 }}>Excluir</th>
                  </tr>
                </thead>
                <tbody>
                  {products.map((product, idx) => {
                    return (
                      <tr key={product.id}>
                        <td>{product.barcode}</td>
                        <td>{product.name}</td>
                        <td>
                          {product.price.toLocaleString("pt-BR", {
                            style: "currency",
                            currency: "BRL",
                          })}
                        </td>
                        <td>
                          <Input
                            type='number'
                            defaultValue={product.quantity}
                            onChange={(e) => {
                              if (e.target.value.length > 0) {
                                const quantity = parseInt(e.target.value);
                                updateProductQuantity(idx, quantity);
                              }
                            }}
                            slotProps={{
                              input: {
                                min: 1,
                              },
                            }}
                          />
                        </td>
                        <td>
                          {(product.quantity * product.price).toLocaleString(
                            "pt-BR",
                            {
                              style: "currency",
                              currency: "BRL",
                            }
                          )}
                        </td>
                        <td>
                          <Box justifyContent='center'>
                            <Button
                              variant='solid'
                              color='danger'
                              onClick={() => {
                                setProducts(
                                  products.filter(
                                    (currProduct) =>
                                      currProduct.id !== product.id
                                  )
                                );
                              }}
                            >
                              <Icon.Trash size={18} />
                            </Button>
                          </Box>
                        </td>
                      </tr>
                    );
                  })}
                </tbody>
              </Table>
            </Sheet>
          </Grid>
        </Grid>
        <Grid container xs={4}>
          <Grid xs={6} textAlign='left'>
            <Typography typography={"h6"} ml={2}>
              Total
            </Typography>
          </Grid>
          <Grid xs={6} textAlign='right'>
            <Typography typography={"h6"} mb={1.5}>
              {totalWithoutDiscount.toLocaleString("pt-BR", {
                style: "currency",
                currency: "BRL",
              })}
            </Typography>
          </Grid>
          <Grid xs={8} textAlign='left' mt={0.8}>
            <Typography typography={"h6"} ml={2}>
              Desconto %
            </Typography>
          </Grid>
          <Grid xs={4} mb={1.5}>
            <Input
              key='discount-percent'
              type='number'
              value={discount}
              onChange={(e) => {
                setDiscount(parseFloat(e.target.value));
              }}
              slotProps={{
                input: {
                  min: 0,
                },
              }}
            />
          </Grid>
          <Grid xs={6} textAlign='left'>
            <Typography typography={"h6"} ml={2}>
              Total c/ Desconto
            </Typography>
          </Grid>
          <Grid xs={6} textAlign='right'>
            <Typography typography={"h6"} mb={1.5}>
              {totalWithDiscount.toLocaleString("pt-BR", {
                style: "currency",
                currency: "BRL",
              })}
            </Typography>
          </Grid>
          <Grid xs={12} ml={2}>
            <Sheet
              className='OrderTableContainer'
              variant='outlined'
              sx={sheetSx}
            >
              <Table
                aria-labelledby='tableTitle'
                stickyHeader
                hoverRow
                sx={tableSx}
              >
                <thead>
                  <tr>
                    <th style={{ width: 120, padding: 12 }}>Forma Pagto.</th>
                    <th style={{ width: 120, padding: 12 }}>Valor</th>
                  </tr>
                </thead>
                <tbody>
                  {payments.map((payment, idx) => {
                    return (
                      <tr key={payment.id}>
                        <td>{payment.name}</td>
                        <td>
                          <Input
                            key={idx}
                            type='number'
                            value={payment.value}
                            onChange={(e) => {
                              if (e.target.value.length > 0) {
                                const value = parseFloat(e.target.value);
                                handlePaymentChange(idx, value);
                              } else {
                                const value = "";
                                handlePaymentChange(idx, value);
                              }
                            }}
                            slotProps={{
                              input: {
                                min: 0,
                              },
                            }}
                          />
                        </td>
                      </tr>
                    );
                  })}
                </tbody>
              </Table>
            </Sheet>
          </Grid>
          <Grid xs={6} textAlign='left'>
            <Typography typography={"h6"} ml={2} mt={1}>
              Total Pago
            </Typography>
          </Grid>
          <Grid xs={6} textAlign='right'>
            <Typography typography={"h6"} mt={1}>
              {totalPaid.toLocaleString("pt-BR", {
                style: "currency",
                currency: "BRL",
              })}
            </Typography>
          </Grid>
          <Grid xs={6} textAlign='left'>
            <Typography typography={"h6"} ml={2}>
              Restante
            </Typography>
          </Grid>
          <Grid xs={6} textAlign='right'>
            <Typography typography={"h6"}>
              {remainder.toLocaleString("pt-BR", {
                style: "currency",
                currency: "BRL",
              })}
            </Typography>
          </Grid>
          <Grid xs={12} ml={2} mt={2}>
            <Box display='flex' justifyContent='flex-end'>
              <Button onClick={createSale} loading={loading}>
                Finalizar Venda
              </Button>
            </Box>
          </Grid>
        </Grid>
      </Grid>
    </>
  );
}
