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

const { Text } = Typography;

const ENTITY_LABEL = 'Customers'; // e.g. 'State', 'District'
const ENTITY_ENDPOINT = ENDPOINTS.CUSTOMERS; // e.g. ENDPOINTS.STATES

interface RowResult {
  row: number;
  name: string;
  status: 'imported' | 'skipped';
  reason?: string;
}

interface DataRecord {
  key: number;
  name: string;
  tamilName: string;
  mobileNo: string;
  address: string;
  status: boolean;
  stateId: string;
  districtId: string;
  openingBalance: string | number;
  state?: {
    id: string;
    name: string;
    tamilName: string | null;
  };
  district?: {
    id: string;
    name: string;
    tamilName: string | null;
  };
}

interface DistrictOption {
  id: string;
  name: string;
  tamilName: string | null;
}

interface StateOption {
  id: string;
  name: string;
  tamilName: string | null;
  districts: DistrictOption[];
}

const Customers = () => {
  const [form] = Form.useForm();
  const [open, setOpen] = useState(false);
  // null = "Add" mode. Holds the record's id while editing.
  const [editingId, setEditingId] = useState<string | null>(null);
  const [searchText, setSearchText] = useState('');
  // null = "All" (no status filter sent to backend)
  const [statusFilter, setStatusFilter] = useState<boolean | null>(null);
  const [data, setData] = useState<DataRecord[]>([]);
  const [loading, setLoading] = useState<boolean>(false);
  // statuses stays exactly as the API returns it: { "Active": true, "Inactive": false }
  const [statuses, setStatuses] = useState<Record<string, boolean>>({});
  // states used to populate the "State" dropdown in the Add/Edit form.
  // Each state carries its own `districts` array (nested response).
  const [states, setStates] = useState<StateOption[]>([]);
  // districts available for whichever state is currently selected in the form
  const [districtOptions, setDistrictOptions] = useState<DistrictOption[]>([]);
  const [pagination, setPagination] = useState({
    current: 1,
    pageSize: Number(import.meta.env.VITE_PAGE_SIZE) || 10,
    total: 0,
    totalPages: 0,
  });

  // ── Import modal state ──
  const [importOpen, setImportOpen] = useState(false);
  const [importLoading, setImportLoading] = useState(false);
  const [importFile, setImportFile] = useState<File | null>(null);
  const [importResults, setImportResults] = useState<{ importedCount: number; skippedCount: number; results: RowResult[] } | null>(null);
  const fileInputRef = useRef<HTMLInputElement>(null);

  // ── Import handlers ──────────────────────────────────────────
  const handleOpenImport = () => {
    setImportFile(null);
    setImportResults(null);
    setImportOpen(true);
  };

  const handleDownloadTemplate = async () => {
    try {
      const response = await jwtAxios.get(ENDPOINTS.CUSTOMERS_IMPORT_TEMPLATE, { responseType: 'blob' });
      const blob = new Blob([response.data], {
        type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
      });
      const url = window.URL.createObjectURL(blob);
      const link = document.createElement('a');
      link.href = url;
      link.download = 'customer-import-template.xlsx';
      document.body.appendChild(link);
      link.click();
      document.body.removeChild(link);
      window.URL.revokeObjectURL(url);
    } catch {
      message.error('Failed to download template');
    }
  };

  const handleImportSave = async () => {
    if (!importFile) {
      message.warning('Please choose an Excel file first.');
      return;
    }
    setImportLoading(true);
    try {
      const formData = new FormData();
      formData.append('file', importFile);
      const res = await jwtAxios.post(ENDPOINTS.CUSTOMERS_IMPORT, formData, {
        headers: { 'Content-Type': 'multipart/form-data' },
      });
      setImportResults(res.data);
      message.success(res.data.message);
      fetchData(1, pagination.pageSize, '');
    } catch (err: any) {
      message.error(err.response?.data?.message || 'Import failed');
    } finally {
      setImportLoading(false);
    }
  };

  const handleAdd = () => {
    setEditingId(null);
    form.resetFields();
    setDistrictOptions([]);
    setOpen(true);
  };

  // Edit button click — GET the single record by id, then populate the
  // same form/modal used for "Add". We just switch modes with editingId.
  const handleEdit = async (id: string) => {
    setLoading(true);
    try {
      const res = await jwtAxios.get(`${ENTITY_ENDPOINT}/${id}`);
      // Adjust this line if your single-record response is wrapped
      // differently (e.g. res.data.result.data instead of res.data.result).
      const record = res.data?.result ?? res.data;

      // Populate the district dropdown for the record's state BEFORE
      // setting the form's districtId, otherwise the Select won't find
      // a matching option to display.
      const matchedState = states.find((s) => s.id === record.stateId);
      setDistrictOptions(matchedState?.districts || []);

      form.setFieldsValue({
        name: record.name,
        tamilName: record.tamilName,
        mobileNo: record.mobileNo,
        address: record.address ?? '',
        status: record.status,
        stateId: record.stateId,
        districtId: record.districtId,
        openingBalance: Number(record.openingBalance) || 0,
      });

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

  // -----------------------------
  // Fetch statuses — ONLY ONCE on mount. This never changes after load,
  // so it does not belong inside fetchData (which runs on every
  // search / page change).
  // -----------------------------
  const fetchStatuses = async () => {
    try {
      const statusRes = await jwtAxios.get(ENDPOINTS.STATUS);
      // Response shape is already { "Active": true, "Inactive": false }
      setStatuses(statusRes.data || {});
    } catch (err: any) {
      message.error(err.response?.data?.message || 'Failed to fetch statuses');
      setStatuses({});
    }
  };

  // -----------------------------
  // Fetch states + their nested districts — ONLY ONCE on mount, same
  // reasoning as statuses. Used to populate the cascading "State" ->
  // "District" dropdowns in the Add/Edit form.
  // -----------------------------
  const fetchStates = async () => {
    try {
      const res = await jwtAxios.get(ENDPOINTS.SUPPLIER_STATE_DISTRICTS);
      // Response shape: { message, result: [ { id, name, tamilName, districts: [...] }, ... ] }
      setStates(res.data?.result || []);
    } catch (err: any) {
      message.error(err.response?.data?.message || 'Failed to fetch states');
      setStates([]);
    }
  };

  // -----------------------------
  // Fetch list — runs on initial load, page change, page-size change,
  // and whenever a search or status filter is triggered.
  // -----------------------------
  const fetchData = async (
    page: number = pagination.current,
    limit: number = pagination.pageSize,
    search: string = searchText,
    status: boolean | null | undefined = statusFilter
  ) => {
    setLoading(true);

    try {
      // Only add "status" to the query string when a filter is actually
      // selected. null / undefined means no status param at all.
      let url = ENTITY_ENDPOINT + `?page=${page}&limit=${limit}&search=${search}`;
      if (status !== null && status !== undefined) {
        url += `&status=${status}`; // sends true or false
      }

      const res = await jwtAxios.get(url);
      // message.success(res?.data?.message);
      // Response shape: { message, result: { data: [...], meta: { total, page, limit, totalPages } } }
      const records = res.data?.result?.data || [];
      const meta = res.data?.result?.meta || {};

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

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

  // Initial load: statuses + states once each, plus first page of records.
  useEffect(() => {
    fetchStatuses();
    fetchStates();
    fetchData(1, pagination.pageSize, '');
  }, []);

  // -----------------------------
  // Search — simple & easy to follow:
  // 1. onChange just updates the input's text (what you see typed).
  // 2. onSearch (Enter key or the search icon) actually triggers the API call,
  //    and resets pagination back to page 1 since it's a new result set.
  // No debounce, no extra state — one function does the work.
  // -----------------------------
  const handleSearch = (value: string) => {
    fetchData(1, pagination.pageSize, value, statusFilter);
  };

  // Status dropdown — same idea as search: pick a value, refetch from
  // page 1, using the current search text so both filters combine.
  const handleStatusFilterChange = (value: boolean | null | undefined) => {
    const status = value ?? null;

    setStatusFilter(status);
    fetchData(1, pagination.pageSize, searchText, status);
  };

  // State dropdown inside the Add/Edit form — when a state is picked,
  // populate the District dropdown from that state's nested `districts`
  // array and clear any previously selected district (it likely belongs
  // to the old state).
  const handleStateChange = (stateId: string) => {
    const selectedState = states.find((s) => s.id === stateId);
    setDistrictOptions(selectedState?.districts || []);
    form.setFieldValue('districtId', undefined); // clear old district selection
  };

  // Delete — actual API call happens only after the user confirms
  // in the Popconfirm popup (see the Actions column below).
  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, statusFilter);
    } catch (err: any) {
      message.error(err.response?.data?.message || `Failed to delete ${ENTITY_LABEL.toLowerCase()}`);
    } finally {
      setLoading(false);
    }
  };

  const handleSubmit = async (values: any) => {
    setLoading(true);

    try {
      const payload = {
        name: values.name,
        tamilName: values.tamilName,
        mobileNo: values.mobileNo,
        address: values.address,
        stateId: values.stateId,
        districtId: values.districtId,
        openingBalance: values.openingBalance,
        status: values.status,
      };

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

      message.success(
        response.data?.message ||
        `${ENTITY_LABEL} ${editingId ? 'updated' : 'added'} successfully`
      );
      setOpen(false);
      setEditingId(null);
      form.resetFields();
      setDistrictOptions([]);
      fetchData(pagination.current, pagination.pageSize, searchText, statusFilter); // refresh current view only
    } 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 ${editingId ? 'update' : 'add'} ${ENTITY_LABEL.toLowerCase()}`
        );
      }
    } finally {
      setLoading(false);
    }
  };

  const columns = [
    {
      title: 'ID',
      dataIndex: 'id',
      render: (id: string) => {
        return id;
      }
    },
    {
      title: 'Name',
      dataIndex: 'name',
    },
    {
      title: 'Tamil Name',
      dataIndex: 'tamilName',
      render: (tamilName: string | null) =>
        tamilName || <Tag color="orange">-</Tag>,
    },
    {
      title: 'Mobile No',
      dataIndex: 'mobileNo',
    },
    {
      title: 'State',
      dataIndex: 'state',
      render: (state: DataRecord['state']) =>
        state ? `${state.name}${state.tamilName ? `(${state.tamilName})` : ''}` : '-',
    },
    {
      title: 'District',
      dataIndex: 'district',
      render: (district: DataRecord['district']) =>
        district ? `${district.name}${district.tamilName ? `(${district.tamilName})` : ''}` : '-',
    },
    {
      title: 'Opening Balance',
      dataIndex: 'openingBalance',
      render: (value: string | number) => {
        const num = Number(value);
        return !isNaN(num) ? num.toFixed(2) : '-';
      },
    },
    {
      title: 'Outstanding Balance',
      dataIndex: 'outstandingBalance',
      render: (value: string | number) => {
        const num = Number(value);
        return !isNaN(num) ? num.toFixed(2) : '-';
      },
    },
    {
      title: 'Status',
      dataIndex: 'status',
      render: (status: boolean) => (
        <Tag color={status ? 'green' : 'red'}>{status ? 'Active' : 'Inactive'}</Tag>
      ),
    },
    {
      title: 'Actions',
      render: (_: any, record: any) => (
        <Space>
          <Popover content="Edit">
            <Button type="link" icon={<EditOutlined />} onClick={() => handleEdit(record.id)}>
            </Button>
          </Popover>
          <Popover content="Delete">
            <Popconfirm
              title={`Delete ${ENTITY_LABEL.toLowerCase()}`}
              description={`Are you sure you want to delete "${record.name}"?`}
              okText="Delete"
              cancelText="Cancel"
              okButtonProps={{ danger: true }}
              onConfirm={() => handleDelete(record.id)} // API call fires only after confirm
            >
              <Button danger type="link" icon={<DeleteOutlined />}>
              </Button>
            </Popconfirm>
          </Popover>
        </Space>
      ),
    },
  ];

  return (
    <div>
      <Spin spinning={loading}>
        <AppContainer
          title={`${ENTITY_LABEL}`}
          headerAction={
            <Space>
              <Button
                icon={<UploadOutlined />}
                onClick={handleOpenImport}
              >
                Import
              </Button>
              <Button
                type="primary"
                icon={<PlusOutlined />}
                onClick={handleAdd}
                className="bg-green-600"
              >
                Add {ENTITY_LABEL}
              </Button>
            </Space>
          }
        >
          {/* Toolbar Section */}
          <div className="flex justify-between items-center mb-4 pb-4 border-b border-gray-200">
            <Space>
              <Select
                placeholder={
                  <>
                    <FilterOutlined /> Status
                  </>
                }
                allowClear
                style={{ width: 150 }}
                value={statusFilter}
                onChange={handleStatusFilterChange} // fires when a status is picked
                onClear={() => handleStatusFilterChange(undefined)} // back to "All"
                options={Object.entries(statuses).map(([label, value]) => ({
                  label,
                  value, // boolean: true / false, sent to backend as-is
                }))}
              />
              <Input.Search
                placeholder="Search..."
                value={searchText}
                onChange={(e) => {
                  const val = e.target.value;
                  setSearchText(val);
                  if (!val) {
                    handleSearch('');
                  }
                }}
                onSearch={handleSearch}
                allowClear
                style={{ width: 200 }}
              />

            </Space>
            <div >
              <Tag color="cyan">{pagination.total} {ENTITY_LABEL.toLowerCase()} </Tag>
            </div>
          </div>

          {/* Table Section */}
          <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={(pageInfo) => {
              fetchData(pageInfo.current!, pageInfo.pageSize!, searchText, statusFilter);
            }}
          />
          <div className="text-center mt-2">
            <Tag color="cyan">
              Page {pagination.current} of {pagination.totalPages}
            </Tag>
          </div>
        </AppContainer>

        <Modal
          title={editingId ? `Edit ${ENTITY_LABEL}` : `Add ${ENTITY_LABEL}`}
          open={open}
          onCancel={() => {
            setOpen(false);
            setEditingId(null);
            setDistrictOptions([]);
          }}
          onOk={() => form.submit()}
          confirmLoading={loading}
          okText="Submit"
        >
          <Form form={form} layout="vertical" onFinish={handleSubmit}>
            <Row gutter={16}>
              <Col xs={24} sm={24} md={12}>
                <Form.Item label="Name" name="name" rules={[{ required: true }]}>
                  <Input />
                </Form.Item>
              </Col>

              <Col xs={24} sm={24} md={12}>
                <Form.Item label="Tamil Name" name="tamilName" rules={[{ required: false }]}>
                  <Input />
                </Form.Item>
              </Col>

              <Col xs={24} sm={24} md={12}>
                <Form.Item
                  label="Mobile No"
                  name="mobileNo"
                  rules={[
                    { required: true },
                    {
                      pattern: /^[0-9]{10}$/,
                      message: 'Enter a valid 10-digit mobile number',
                    },
                  ]}
                >
                  <Input maxLength={10} />
                </Form.Item>
              </Col>

              <Col xs={24} sm={24} md={12}>
                <Form.Item
                  label="Opening Balance"
                  name="openingBalance"
                  initialValue={0}
                  rules={[{ required: true }]}
                >
                  <InputNumber
                    style={{ width: '100%' }}
                    disabled={editingId !== null}
                    min={0}
                    step={1}
                    precision={2}
                  />
                </Form.Item>
              </Col>

              <Col span={24}>
                <Form.Item label="Address" name="address" rules={[{ required: true }]}>
                  <Input.TextArea rows={2} />
                </Form.Item>
              </Col>

              <Col xs={24} sm={24} md={12}>
                <Form.Item label="State" name="stateId" rules={[{ required: true }]}>
                  <Select
                    showSearch
                    placeholder="Select a state"
                    optionFilterProp="label"
                    filterOption={(input, option) =>
                      (option?.label ?? '').toLowerCase().includes(input.toLowerCase())
                    }
                    onChange={handleStateChange}
                    options={states.map((state) => ({
                      label: state.name,
                      value: state.id,
                    }))}
                  />
                </Form.Item>
              </Col>

              <Col xs={24} sm={24} md={12}>
                <Form.Item label="District" name="districtId" rules={[{ required: true }]}>
                  <Select
                    showSearch
                    placeholder="Select a district"
                    optionFilterProp="label"
                    filterOption={(input, option) =>
                      (option?.label ?? '').toLowerCase().includes(input.toLowerCase())
                    }
                    disabled={districtOptions.length === 0}
                    notFoundContent="Select a state first"
                    options={districtOptions.map((district) => ({
                      label: district.name,
                      value: district.id,
                    }))}
                  />
                </Form.Item>
              </Col>

              <Col xs={24} sm={24} md={12}>
                <Form.Item
                  label="Status"
                  name="status"
                  initialValue={true}
                  rules={[{ required: true }]}
                >
                  <Select
                    options={Object.entries(statuses).map(([label, value]) => ({
                      label,
                      value,
                    }))}
                  />
                </Form.Item>
              </Col>
            </Row>
          </Form>
        </Modal>

        {/* ── Bulk Import Modal ── */}
        <Modal
          title="Customer Bulk Import"
          open={importOpen}
          onCancel={() => setImportOpen(false)}
          footer={null}
          width={780}
          destroyOnHidden
        >
          <div style={{ display: 'flex', gap: 24 }}>
            {/* Left panel */}
            <div style={{ flex: 1 }}>
              <div style={{ marginBottom: 16 }}>
                <Text strong>Upload File <span style={{ color: 'red' }}>*</span></Text>
                <div style={{ marginTop: 8, display: 'flex', alignItems: 'center', gap: 8 }}>
                  <Button
                    icon={<UploadOutlined />}
                    onClick={() => fileInputRef.current?.click()}
                    style={{ background: '#1d1b4b', color: '#fff', border: 'none' }}
                  >
                    CHOOSE FILE
                  </Button>
                  <Text type={importFile ? 'success' : 'secondary'}>
                    {importFile ? importFile.name : 'No file chosen'}
                  </Text>
                  <input
                    ref={fileInputRef}
                    type="file"
                    accept=".xlsx"
                    style={{ display: 'none' }}
                    onChange={(e) => {
                      const file = e.target.files?.[0] ?? null;
                      setImportFile(file);
                      setImportResults(null);
                      e.target.value = '';
                    }}
                  />
                </div>
              </div>

              <Button
                icon={<DownloadOutlined />}
                type="link"
                style={{ paddingLeft: 0, marginBottom: 16 }}
                onClick={handleDownloadTemplate}
              >
                Download Template
              </Button>

              {/* Import results summary */}
              {importResults && (
                <div style={{ marginBottom: 12 }}>
                  <Alert
                    type={importResults.skippedCount > 0 ? 'warning' : 'success'}
                    message={`${importResults.importedCount} imported, ${importResults.skippedCount} skipped`}
                    style={{ marginBottom: 8 }}
                  />
                  {importResults.results.filter(r => r.status === 'skipped').length > 0 && (
                    <div style={{ maxHeight: 160, overflowY: 'auto', fontSize: 12 }}>
                      {importResults.results.filter(r => r.status === 'skipped').map(r => (
                        <div key={r.row} style={{ color: '#cf1322', marginBottom: 4 }}>
                          Row {r.row} — <strong>{r.name}</strong>: {r.reason}
                        </div>
                      ))}
                    </div>
                  )}
                </div>
              )}

              <div style={{ display: 'flex', gap: 12, marginTop: 8 }}>
                <Button danger onClick={() => setImportOpen(false)} style={{ flex: 1 }}>
                  Cancel
                </Button>
                <Button
                  type="primary"
                  loading={importLoading}
                  onClick={handleImportSave}
                  style={{ flex: 1, background: '#1d1b4b', border: 'none' }}
                >
                  Save
                </Button>
              </div>
            </div>

            {/* Right panel — instructions */}
            <div
              className="
                flex-1
                bg-[#fafafa]
                border border-[#e8e8e8]
                rounded-lg
                p-4
                text-[13px]
              "
            >
              <Text strong>Important Instructions:</Text>
              <ul style={{ marginTop: 10, paddingLeft: 18, lineHeight: 2 }}>
                <li>Upload only Excel (.xlsx) files.</li>
                <li>All required columns must be present in the sheet.</li>
                <li>Maximum file size: 5 MB.</li>
                <li><strong>Customer Name</strong> and <strong>Mobile No</strong> are required.</li>
                <li><strong>Mobile No</strong> must be a valid 10-digit number.</li>
                <li><strong>State Name</strong> must match an existing State in the system.</li>
                <li><strong>District Name</strong> must match an existing District for the specified State.</li>
                <li style={{ color: '#cf1322' }}>
                  Duplicate records are checked on the combination of <strong>Customer Name + Mobile No</strong> (same name with different mobile or same mobile with different name is allowed).
                </li>
                <li>All imported customers are set to <strong>Active</strong> by default.</li>
              </ul>
            </div>
          </div>
        </Modal>
      </Spin>
    </div>
  );
};

export default Customers;