import { useEffect, useState } from 'react';
import {
  Button,
  Col,
  DatePicker,
  Form,
  Input,
  InputNumber,
  Modal,
  Row,
  Select,
  Space,
  Spin,
  Table,
  Tag,
  message,
  Descriptions,
  Popover,
  Popconfirm,
} from 'antd';
import {
  PlusOutlined,
  DownloadOutlined,
  EyeOutlined,
  EditOutlined,
  DeleteOutlined,
  WhatsAppOutlined,
} from '@ant-design/icons';
import dayjs, { Dayjs } from 'dayjs';
import { AppContainer } from '../../components/AppContainer';
import jwtAxios from '../../api/axiosInstance';
import { ENDPOINTS } from '../../api/endpoints';

const ENTITY_LABEL = 'Customer Receipt';
const ENTITY_ENDPOINT = ENDPOINTS.CUSTOMER_RECEIPTS;
const ENTITY_EXPORT = ENDPOINTS.CUSTOMER_RECEIPTS_EXPORT;

interface DataRecord {
  key: string;
  id: string;
  receiptDate: string;
  amount: string;
  paymentMode: string;
  referenceNo: string;
  remarks: string;
  customerId: string;
  customer?: { name: string; outstandingBalance?: string | number };
  isWhatsappMessageSent?: boolean;
}

interface CustomerOption {
  id: string;
  name: string;
  outstandingBalance: string | number;
}

const { RangePicker } = DatePicker;

export const CustomerPayments = () => {
  const [form] = Form.useForm();
  const [open, setOpen] = useState(false);
  const [searchText, setSearchText] = useState('');
  const [dateRange, setDateRange] = useState<[Dayjs, Dayjs] | null>(null);
  const [data, setData] = useState<DataRecord[]>([]);
  const [loading, setLoading] = useState<boolean>(false);
  const [metaLoading, setMetaLoading] = useState<boolean>(false);
  const [exportLoading, setExportLoading] = useState<boolean>(false);
  const [exportPdfLoading, setExportPdfLoading] = useState<boolean>(false);
  const [customers, setCustomers] = useState<CustomerOption[]>([]);
  const [selectedCustomerBalance, setSelectedCustomerBalance] = useState<number | null>(null);
  const [paymentModes, setPaymentModes] = useState<{ label: string, value: string }[]>([]);

  const [viewOpen, setViewOpen] = useState(false);
  const [viewLoading, setViewLoading] = useState(false);
  const [viewRecord, setViewRecord] = useState<any>(null);

  const [isEditMode, setIsEditMode] = useState(false);
  const [editId, setEditId] = useState<string | null>(null);
  const [initialEditAmount, setInitialEditAmount] = useState<number>(0);

  const [pagination, setPagination] = useState({
    current: 1,
    pageSize: Number(import.meta.env.VITE_PAGE_SIZE) || 10,
    total: 0,
    totalPages: 0,
  });

  const handleExportPdf = async () => {
    if (!data || data.length === 0) {
      message.warning('No data available to export');
      return;
    }
    setExportPdfLoading(true);
    try {
      const params = new URLSearchParams();
      if (searchText) params.set('search', searchText);
      if (dateRange) {
        params.set('dateFrom', dateRange[0].format('YYYY-MM-DD'));
        params.set('dateTo', dateRange[1].format('YYYY-MM-DD'));
      }

      const response = await jwtAxios.get(
        `${ENDPOINTS.CUSTOMER_RECEIPTS_EXPORT_PDF}?${params.toString()}`,
        { responseType: 'blob' }
      );

      const disposition = response.headers['content-disposition'];
      let fileName = `customer-receipts-${dayjs().format('YYYY-MM-DD')}.pdf`;
      if (disposition) {
        const match = disposition.match(/filename="?([^"\n;]+)"?/i);
        if (match?.[1]) fileName = match[1];
      }

      const blob = new Blob([response.data], { type: 'application/pdf' });
      const objectUrl = window.URL.createObjectURL(blob);
      const link = document.createElement('a');
      link.href = objectUrl;
      link.download = fileName;
      document.body.appendChild(link);
      link.click();
      document.body.removeChild(link);
      window.URL.revokeObjectURL(objectUrl);

      message.success('PDF exported successfully');
    } catch (err: any) {
      message.error(err.response?.data?.message || 'Failed to export PDF');
    } finally {
      setExportPdfLoading(false);
    }
  };

  const handleExport = async () => {
    if (!data || data.length === 0) {
      message.warning('No data available to export');
      return;
    }
    setExportLoading(true);
    try {
      const params = new URLSearchParams();
      if (searchText) params.set('search', searchText);
      if (dateRange) {
        params.set('dateFrom', dateRange[0].format('YYYY-MM-DD'));
        params.set('dateTo', dateRange[1].format('YYYY-MM-DD'));
      }

      const response = await jwtAxios.get(
        `${ENTITY_EXPORT}?${params.toString()}`,
        { responseType: 'blob' }
      );

      const disposition = response.headers['content-disposition'];
      let fileName = `customer-receipts-${dayjs().format('YYYY-MM-DD_HHmmss')}.xlsx`;
      if (disposition) {
        const match = disposition.match(/filename\*?=(?:UTF-8'')?"?([^"\n;]+)"?/i);
        if (match?.[1]) fileName = decodeURIComponent(match[1]);
      }

      const blob = new Blob([response.data], {
        type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
      });
      const objectUrl = window.URL.createObjectURL(blob);
      const link = document.createElement('a');
      link.href = objectUrl;
      link.download = fileName;
      document.body.appendChild(link);
      link.click();
      document.body.removeChild(link);
      window.URL.revokeObjectURL(objectUrl);

      message.success('Customer receipts exported successfully');
    } catch (err: any) {
      message.error(err.response?.data?.message || 'Failed to export customer receipts');
    } finally {
      setExportLoading(false);
    }
  };

  const handleAdd = async () => {
    form.resetFields();
    setSelectedCustomerBalance(null);
    setIsEditMode(false);
    setEditId(null);
    setInitialEditAmount(0);
    form.setFieldsValue({ receiptDate: dayjs() });
    setOpen(true);
    // Refresh meta dropdown data when opening modal
    await Promise.all([fetchCustomers(), fetchPaymentModes()]);
  };

  const handleView = async (id: string) => {
    setViewLoading(true);
    setViewOpen(true);
    try {
      const res = await jwtAxios.get(`${ENTITY_ENDPOINT}/${id}`);
      const record = res.data?.result ?? res.data;
      setViewRecord(record);
    } catch (err: any) {
      message.error(err.response?.data?.message || `Failed to load ${ENTITY_LABEL.toLowerCase()}`);
      setViewOpen(false);
    } finally {
      setViewLoading(false);
    }
  };

  const fetchCustomers = async () => {
    try {
      setMetaLoading(true);
      const res = await jwtAxios.get(`${ENTITY_ENDPOINT}/meta`);
      const records = res.data?.result?.customers || [];

      const mapped = records.map((c: any) => ({
        id: c.id.toString(),
        name: c.name,
        outstandingBalance: c.outstandingBalance,
      }));
      setCustomers(mapped);
      return mapped;
    } catch (err: any) {
      message.error(err.response?.data?.message || 'Failed to fetch customers');
      return [];
    } finally {
      setMetaLoading(false);
    }
  };

  const fetchData = async (
    page: number = pagination.current,
    limit: number = pagination.pageSize,
    search: string = searchText,
    range: [Dayjs, Dayjs] | null = dateRange
  ) => {
    setLoading(true);
    try {
      let url = `${ENTITY_ENDPOINT}?page=${page}&limit=${limit}&search=${search}`;
      if (range) {
        url += `&dateFrom=${range[0].format('YYYY-MM-DD')}&dateTo=${range[1].format('YYYY-MM-DD')}`;
      }

      const res = await jwtAxios.get(url);
      const records = res.data?.result?.data || [];
      const metaInfo = res.data?.result?.meta || {};

      const formattedData = records.map((item: any) => ({
        key: item.id,
        ...item,
      }));

      setData(formattedData);
      setPagination((prev) => ({
        ...prev,
        current: metaInfo.page ?? page,
        pageSize: metaInfo.limit ?? limit,
        total: metaInfo.total ?? prev.total,
        totalPages: metaInfo.totalPages ?? prev.totalPages,
      }));
    } catch (err: any) {
      message.error(err.response?.data?.message || 'Failed to fetch data');
      setData([]);
    } finally {
      setLoading(false);
    }
  };

  const fetchPaymentModes = async () => {
    try {
      const res = await jwtAxios.get(ENDPOINTS.PAYMENTMODES);
      const modes = res.data?.PaymentMode || {};
      setPaymentModes(Object.entries(modes).map(([key, value]) => ({ label: key, value: String(value) })));
    } catch (err: any) {
      console.error('Failed to fetch payment modes', err);
    }
  };

  useEffect(() => {
    fetchCustomers();
    fetchData(1, pagination.pageSize, '');
    fetchPaymentModes();
  }, []);

  const handleSearch = (value: string) => {
    fetchData(1, pagination.pageSize, value, dateRange);
  };

  const handleDateRangeChange = (values: any) => {
    const range = values ? (values as [Dayjs, Dayjs]) : null;
    setDateRange(range);
    fetchData(1, pagination.pageSize, searchText, range);
  };

  const executeSubmit = async (values: any) => {
    setLoading(true);
    try {
      const payload = {
        receiptDate: values.receiptDate?.format('YYYY-MM-DD'),
        customerId: values.customerId,
        amount: values.amount,
        paymentMode: values.paymentMode,
        referenceNo: values.referenceNo,
        remarks: values.remarks,
      };

      const response =
        isEditMode && editId
          ? await jwtAxios.put(`${ENTITY_ENDPOINT}/${editId}`, payload)
          : await jwtAxios.post(ENTITY_ENDPOINT, payload);

      message.success(
        response.data?.message ||
        `${ENTITY_LABEL} ${isEditMode ? 'updated' : 'added'} successfully`
      );
      setOpen(false);
      form.resetFields();
      setSelectedCustomerBalance(null);
      setIsEditMode(false);
      setEditId(null);
      setInitialEditAmount(0);

      fetchCustomers();
      fetchData(pagination.current, pagination.pageSize, searchText, dateRange);
    } catch (err: any) {
      const responseData = err.response?.data;
      const fieldErrors = responseData?.errors;

      if (fieldErrors && typeof fieldErrors === 'object') {
        form.setFields(
          Object.entries(fieldErrors).map(([name, error]) => ({
            name,
            errors: [String(error)],
          }))
        );
        message.error(responseData?.message || 'Please fix the highlighted fields');
      } else {
        message.error(
          responseData?.message ||
          `Failed to ${isEditMode ? 'update' : 'add'} ${ENTITY_LABEL.toLowerCase()}`
        );
      }
    } finally {
      setLoading(false);
    }
  };

  const handleSubmit = async (values: any) => {
    const selectedCustomer = customers.find((c) => c.id === values.customerId);
    const custBalance = Number(selectedCustomer?.outstandingBalance || 0);
    const amount = Number(values.amount || 0);
    const maxAllowed = isEditMode ? custBalance + initialEditAmount : custBalance;

    if (amount > maxAllowed) {
      message.error(
        `Receipt amount (₹${amount.toFixed(2)}) cannot exceed the customer's outstanding balance (₹${maxAllowed.toFixed(2)}).`
      );
      return;
    }

    if (isEditMode) {
      await executeSubmit(values);
    } else {
      Modal.confirm({
        title: 'Confirm Customer Receipt',
        content: 'Are you sure you want to submit this customer receipt?',
        okText: 'Submit',
        cancelText: 'Cancel',
        okButtonProps: { className: 'bg-green-600' },
        onOk: async () => {
          await executeSubmit(values);
        },
      });
    }
  };

  const handleWhatsapp = async (receiptId: string) => {
    setLoading(true);
    try {
      await jwtAxios.post(ENDPOINTS.CUSTOMER_RECEIPTS_WHATSAPP_MESSAGE(receiptId));
      message.success('WhatsApp message sent successfully');
      fetchData(pagination.current, pagination.pageSize, searchText, dateRange);
    } catch (err: any) {
      message.error(err?.response?.data?.message || 'Failed to send WhatsApp message');
    } finally {
      setLoading(false);
    }
  };

  const paymentModeColor = (mode: string) => {
    switch (mode) {
      case 'CASH': return 'green';
      case 'BANK': return 'blue';
      case 'UPI': return 'purple';
      default: return 'default';
    }
  };

  const columns = [
    {
      title: 'Receipt Date',
      dataIndex: 'receiptDate',
      render: (date: string) => (date ? dayjs(date).format('DD MMM YYYY') : '-'),
    },
    {
      title: 'Customer',
      dataIndex: 'customer',
      render: (customer: DataRecord['customer']) => (customer ? customer.name : '-'),
    },
    {
      title: 'Amount',
      dataIndex: 'amount',
      render: (amount: string) => Number(amount).toFixed(2),
    },
    {
      title: 'Payment Mode',
      dataIndex: 'paymentMode',
      render: (mode: string) => <Tag color={paymentModeColor(mode)}>{mode}</Tag>,
    },
    {
      title: 'Reference No',
      dataIndex: 'referenceNo',
      render: (ref: string) => ref || '-',
    },
    {
      title: 'Created By',
      dataIndex: 'createdByName',
      render: (createdBy: string) => createdBy || '-',
    },
    {
      title: 'Remarks',
      dataIndex: 'remarks',
      render: (remarks: string) => remarks || '-',
    },
    {
      title: 'Actions',
      render: (_: any, record: any) => (
        <Space>
          <Popover content="View">
            <Button type="link" icon={<EyeOutlined />} onClick={() => handleView(record.id)} />
          </Popover>
          <Popover content="Edit">
            <Button type="link" icon={<EditOutlined />} onClick={() => handleEdit(record.id)} />
          </Popover>
          <Popconfirm
            title={`Delete ${ENTITY_LABEL.toLowerCase()}`}
            description={`Are you sure you want to delete this payment?`}
            okText="Delete"
            cancelText="Cancel"
            okButtonProps={{ danger: true }}
            onConfirm={() => handleDelete(record.id)}
          >
            <Button danger type="link" icon={<DeleteOutlined />} />
          </Popconfirm>

          <Popover
            content={
              record.isWhatsappMessageSent
                ? "Receipt already sent"
                : "Share Receipt via WhatsApp"
            }
          >
            <Button
              disabled={record.isWhatsappMessageSent ?? false}
              type="link"
              className={
                record.isWhatsappMessageSent
                  ? "text-gray-400! opacity-60! cursor-not-allowed!"
                  : "text-green-500!"
              }
              icon={<WhatsAppOutlined />}
              onClick={() => handleWhatsapp(record.id)}
            />
          </Popover>
        </Space>
      ),
    },
  ];

  const handleCustomerChange = async (val: string) => {
    if (!val) {
      setSelectedCustomerBalance(null);
      return;
    }
    const cust = customers.find((c) => c.id === val);
    if (cust) {
      setSelectedCustomerBalance(Number(cust.outstandingBalance));
    }
  };

  const handleDelete = async (id: string) => {
    setLoading(true);
    try {
      const res = await jwtAxios.delete(`${ENTITY_ENDPOINT}/${id}`);
      message.success(res.data?.message || `${ENTITY_LABEL} deleted successfully`);
      fetchData(pagination.current, pagination.pageSize, searchText, dateRange);
    } catch (err: any) {
      message.error(err.response?.data?.message || `Failed to delete ${ENTITY_LABEL.toLowerCase()}`);
    } finally {
      setLoading(false);
    }
  };

  const handleEdit = async (id: string) => {
    setLoading(true);
    try {
      const [latestCustomers] = await Promise.all([fetchCustomers(), fetchPaymentModes()]);
      const res = await jwtAxios.get(`${ENTITY_ENDPOINT}/${id}`);
      const record = res.data?.result ?? res.data;

      setIsEditMode(true);
      setEditId(id);
      setInitialEditAmount(Number(record.amount));

      form.setFieldsValue({
        customerId: record.customerId?.toString(),
        receiptDate: record.receiptDate ? dayjs(record.receiptDate) : null,
        amount: Number(record.amount),
        paymentMode: record.paymentMode,
        referenceNo: record.referenceNo,
        remarks: record.remarks,
      });

      const custList = latestCustomers && latestCustomers.length > 0 ? latestCustomers : customers;
      const cust = custList.find((c: any) => c.id === record.customerId?.toString());
      if (cust) {
        setSelectedCustomerBalance(Number(cust.outstandingBalance));
      }

      setOpen(true);
    } catch (err: any) {
      message.error(err.response?.data?.message || `Failed to load ${ENTITY_LABEL.toLowerCase()} for edit`);
    } finally {
      setLoading(false);
    }
  };

  return (
    <div>
      <Spin spinning={loading}>
        <AppContainer
          title={`${ENTITY_LABEL}`}
          headerAction={
            <Space>
              <Button
                icon={<DownloadOutlined />}
                loading={exportLoading}
                style={{ color: '#52c41a', borderColor: '#52c41a' }}
                onClick={handleExport}
              >
                Export
              </Button>
              <Button
                icon={<DownloadOutlined />}
                loading={exportPdfLoading}
                style={{ color: '#cf1322', borderColor: '#cf1322' }}
                onClick={handleExportPdf}
              >
                Export PDF
              </Button>
              <Button
                type="primary"
                icon={<PlusOutlined />}
                onClick={handleAdd}
                className="bg-green-600"
              >
                Add Receipt
              </Button>
            </Space>
          }
        >
          <div className="flex justify-between items-center mb-4 pb-4 border-b border-gray-200">
            <Space>
              <RangePicker value={dateRange as any} onChange={handleDateRangeChange} />
              <Input.Search
                placeholder="Search..."
                value={searchText}
                onChange={(e) => setSearchText(e.target.value)}
                onSearch={handleSearch}
                allowClear
                style={{ width: 200 }}
              />
            </Space>
          </div>

          <Table
            rowKey="key"
            columns={columns}
            dataSource={data}
            loading={loading}
            scroll={{ x: 'max-content', y: 400 }}
            pagination={{
              current: pagination.current,
              pageSize: pagination.pageSize,
              total: pagination.total,
              showSizeChanger: true,
            }}
            onChange={(pag) => {
              setPagination((prev) => ({
                ...prev,
                current: pag.current || 1,
                pageSize: pag.pageSize || 10,
              }));
              fetchData(pag.current, pag.pageSize, searchText, dateRange);
            }}
          />
          <div className="text-center mt-2">
            <Tag color="cyan">
              Page {pagination.current} of {pagination.totalPages}
            </Tag>
          </div>
        </AppContainer>
      </Spin>

      <Modal
        title={isEditMode ? `Edit ${ENTITY_LABEL}` : `Add ${ENTITY_LABEL}`}
        open={open}
        onCancel={() => {
          setOpen(false);
          setIsEditMode(false);
          setEditId(null);
          setInitialEditAmount(0);
        }}
        footer={[
          <Button
            key="cancel"
            onClick={() => {
              setOpen(false);
              setIsEditMode(false);
              setEditId(null);
              setInitialEditAmount(0);
            }}
          >
            Cancel
          </Button>,
          <Button
            key="submit"
            type="primary"
            onClick={() => form.submit()}
            loading={loading}
            className="bg-green-600"
          >
            {isEditMode ? 'Update' : 'Save'}
          </Button>,
        ]}
        width={700}
      >
        <Form form={form} layout="vertical" onFinish={handleSubmit}>
          <Row gutter={16}>
            <Col xs={24} sm={12}>
              <Form.Item
                label="Customer"
                name="customerId"
                rules={[{ required: true, message: 'Please select a customer' }]}
              >
                <Select
                  showSearch
                  placeholder="Select a customer"
                  optionFilterProp="children"
                  onChange={handleCustomerChange}
                  disabled={isEditMode}
                  loading={metaLoading}
                >
                  {customers.map((c) => (
                    <Select.Option key={c.id} value={c.id}>
                      {c.name} {c.outstandingBalance ? `(₹${Number(c.outstandingBalance).toFixed(2)})` : ''}
                    </Select.Option>
                  ))}
                </Select>
              </Form.Item>
              {selectedCustomerBalance !== null && (
                <div style={{ marginBottom: 16, marginTop: -12, fontSize: 12, color: 'gray' }}>
                  Outstanding Balance: <strong style={{ color: selectedCustomerBalance > 0 ? '#cf1322' : '#52c41a' }}>₹{selectedCustomerBalance.toFixed(2)}</strong>
                </div>
              )}
            </Col>

            <Col xs={24} sm={12}>
              <Form.Item
                label="Receipt Date"
                name="receiptDate"
                rules={[{ required: true, message: 'Please select date' }]}
                initialValue={dayjs()}
              >
                <DatePicker style={{ width: '100%' }} />
              </Form.Item>
            </Col>

            <Col xs={24} sm={12}>
              <Form.Item
                label="Amount"
                name="amount"
                rules={[
                  { required: true, message: 'Please enter amount' },
                  {
                    validator: (_, value) => {
                      if (value && selectedCustomerBalance !== null) {
                        const maxAllowed = isEditMode
                          ? selectedCustomerBalance + initialEditAmount
                          : selectedCustomerBalance;

                        if (value > maxAllowed) {
                          return Promise.reject(
                            new Error(`Amount cannot exceed outstanding balance (₹${maxAllowed.toFixed(2)})`)
                          );
                        }
                      }
                      return Promise.resolve();
                    },
                  },
                ]}
              >
                <InputNumber
                  // disabled={isEditMode}
                  style={{ width: '100%' }}
                  min={0.01}
                  step={0.01}
                  placeholder="0.00"
                />
              </Form.Item>
            </Col>

            <Col xs={24} sm={12}>
              <Form.Item
                label="Payment Mode"
                name="paymentMode"
                rules={[{ required: true, message: 'Please select mode' }]}
              >
                <Select placeholder="Select mode" options={paymentModes} />
              </Form.Item>
            </Col>

            <Col xs={24} sm={12}>
              <Form.Item label="Reference No" name="referenceNo">
                <Input placeholder="Txn ID, Cheque No, etc." />
              </Form.Item>
            </Col>

            <Col xs={24}>
              <Form.Item label="Remarks" name="remarks">
                <Input.TextArea rows={2} />
              </Form.Item>
            </Col>
          </Row>
        </Form>
      </Modal>

      <Modal
        title={`${ENTITY_LABEL} Details`}
        open={viewOpen}
        onCancel={() => setViewOpen(false)}
        footer={[
          <Button key="close" onClick={() => setViewOpen(false)}>
            Close
          </Button>,
        ]}
        width={600}
      >
        <Spin spinning={viewLoading}>
          {viewRecord && (
            <Descriptions bordered column={1}>
              <Descriptions.Item label="Receipt Date">
                {viewRecord.receiptDate ? dayjs(viewRecord.receiptDate).format('DD MMM YYYY') : '-'}
              </Descriptions.Item>
              <Descriptions.Item label="Customer">
                {viewRecord.customer?.name}
              </Descriptions.Item>
              <Descriptions.Item label="Amount">
                ₹{Number(viewRecord.amount).toFixed(2)}
              </Descriptions.Item>
              <Descriptions.Item label="Payment Mode">
                <Tag color={paymentModeColor(viewRecord.paymentMode)}>{viewRecord.paymentMode}</Tag>
              </Descriptions.Item>
              <Descriptions.Item label="Reference No">
                {viewRecord.referenceNo || '-'}
              </Descriptions.Item>
              <Descriptions.Item label="Remarks">
                {viewRecord.remarks || '-'}
              </Descriptions.Item>
            </Descriptions>
          )}
        </Spin>
      </Modal>
    </div>
  );
};


