import { useState, useEffect, useCallback, useRef } from 'react';
import {
  Table,
  Button,
  Input,
  Select,
  Tag,
  Space,
  Form,
  Switch,
  Popconfirm,
  message,
  Row,
  Col,
  Slider,
  Segmented,
  Drawer,
  Upload,
  Typography,
  Result,
  Grid,
} from 'antd';
import {
  PlusOutlined,
  EditOutlined,
  DeleteOutlined,
  SearchOutlined,
  EnvironmentOutlined,
  TableOutlined,
  PrinterOutlined,
  DownloadOutlined,
  UploadOutlined,
  ExportOutlined,
  ImportOutlined,
} from '@ant-design/icons';
import type { ColumnsType, TablePaginationConfig } from 'antd/es/table';
import dayjs from 'dayjs';
import { useNavigate, useOutletContext } from 'react-router-dom';
import { api } from '@/lib/api';
import type { AppOutletContext } from '@/components/AppLayout';
import type {
  Cut,
  CutsListResponse,
  CutsListParams,
  CutCategory,
} from '@/types/api';
import { CUT_CATEGORY_LABELS, CUT_CATEGORY_COLORS } from '@/types/api';
import CutEditorMap from '@/components/map/CutEditorMap';

const categoryOptions = Object.entries(CUT_CATEGORY_LABELS).map(([value, label]) => ({
  value,
  label,
}));

export default function CutsPage() {
  const navigate = useNavigate();
  const [cuts, setCuts] = useState<Cut[]>([]);
  const screens = Grid.useBreakpoint();
  const isMobile = !screens.md;
  const [pagination, setPagination] = useState({ page: 1, limit: 20, total: 0, totalPages: 0 });
  const [loading, setLoading] = useState(false);
  const [search, setSearch] = useState('');
  const [debouncedSearch, setDebouncedSearch] = useState('');
  const searchTimerRef = useRef<ReturnType<typeof setTimeout>>(undefined);
  const [categoryFilter, setCategoryFilter] = useState<CutCategory | undefined>();
  const [activeTab, setActiveTab] = useState('table');

  // Create modal
  const [createDrawerOpen, setCreateDrawerOpen] = useState(false);
  const [pendingGeojson, setPendingGeojson] = useState<string | null>(null);
  const [pendingBounds, setPendingBounds] = useState<string | null>(null);
  const [createForm] = Form.useForm();

  // Import modal
  const [importDrawerOpen, setImportDrawerOpen] = useState(false);
  const [importing, setImporting] = useState(false);

  // Edit drawer
  const [editDrawerOpen, setEditDrawerOpen] = useState(false);
  const [editingCut, setEditingCut] = useState<Cut | null>(null);
  const [editForm] = Form.useForm();

  const handleSearchChange = (value: string) => {
    setSearch(value);
    clearTimeout(searchTimerRef.current);
    searchTimerRef.current = setTimeout(() => setDebouncedSearch(value), 300);
  };

  useEffect(() => {
    return () => clearTimeout(searchTimerRef.current);
  }, []);

  const fetchCuts = useCallback(async (params?: CutsListParams) => {
    setLoading(true);
    try {
      const { data } = await api.get<CutsListResponse>('/map/cuts', {
        params: {
          page: params?.page ?? pagination.page,
          limit: params?.limit ?? pagination.limit,
          search: params?.search ?? (debouncedSearch || undefined),
          category: params?.category ?? categoryFilter,
        },
      });
      setCuts(data.cuts);
      setPagination(data.pagination);
    } catch {
      message.error('Failed to load cuts');
    } finally {
      setLoading(false);
    }
  }, [pagination.page, pagination.limit, debouncedSearch, categoryFilter]);

  useEffect(() => {
    fetchCuts({ page: 1 });
  }, [debouncedSearch, categoryFilter]); // eslint-disable-line react-hooks/exhaustive-deps

  const handleTableChange = (pag: TablePaginationConfig) => {
    fetchCuts({ page: pag.current ?? 1, limit: pag.pageSize ?? 20 });
  };

  const handleCreate = async (values: Record<string, unknown>) => {
    try {
      await api.post('/map/cuts', {
        ...values,
        geojson: pendingGeojson,
        bounds: pendingBounds,
      });
      message.success('Cut created');
      setCreateDrawerOpen(false);
      createForm.resetFields();
      setPendingGeojson(null);
      setPendingBounds(null);
      fetchCuts({ page: 1 });
    } catch (err: unknown) {
      const msg =
        (err as { response?: { data?: { error?: { message?: string } } } })
          ?.response?.data?.error?.message || 'Failed to create cut';
      message.error(msg);
    }
  };

  const handleEdit = async (values: Record<string, unknown>) => {
    if (!editingCut) return;
    try {
      await api.put(`/map/cuts/${editingCut.id}`, values);
      message.success('Cut updated');
      setEditDrawerOpen(false);
      setEditingCut(null);
      editForm.resetFields();
      fetchCuts();
    } catch (err: unknown) {
      const msg =
        (err as { response?: { data?: { error?: { message?: string } } } })
          ?.response?.data?.error?.message || 'Failed to update cut';
      message.error(msg);
    }
  };

  const handleExportAll = async () => {
    try {
      const { data } = await api.get('/map/cuts/export-geojson', { responseType: 'blob' });
      const blob = new Blob([JSON.stringify(data)], { type: 'application/geo+json' });
      const url = URL.createObjectURL(blob);
      const a = document.createElement('a');
      a.href = url;
      a.download = 'cuts.geojson';
      a.click();
      URL.revokeObjectURL(url);
      message.success('GeoJSON exported');
    } catch {
      message.error('Export failed');
    }
  };

  const handleExportSingle = async (id: string, name: string) => {
    try {
      const { data } = await api.get(`/map/cuts/${id}/export-geojson`);
      const blob = new Blob([JSON.stringify(data)], { type: 'application/geo+json' });
      const url = URL.createObjectURL(blob);
      const a = document.createElement('a');
      a.href = url;
      a.download = `${name.replace(/\s+/g, '-').toLowerCase()}.geojson`;
      a.click();
      URL.revokeObjectURL(url);
    } catch {
      message.error('Export failed');
    }
  };

  const handleImport = async (file: File) => {
    setImporting(true);
    try {
      const formData = new FormData();
      formData.append('file', file);
      const { data } = await api.post('/map/cuts/import-geojson', formData);
      message.success(`Imported: ${data.success} of ${data.total} features`);
      if (data.failed > 0) {
        message.warning(`${data.failed} features failed to import`);
      }
      setImportDrawerOpen(false);
      fetchCuts({ page: 1 });
    } catch {
      message.error('Import failed');
    } finally {
      setImporting(false);
    }
  };

  const handleDelete = async (id: string) => {
    try {
      await api.delete(`/map/cuts/${id}`);
      message.success('Cut deleted');
      fetchCuts();
    } catch {
      message.error('Failed to delete cut');
    }
  };

  const openEdit = (cut: Cut) => {
    setEditingCut(cut);
    editForm.setFieldsValue({
      name: cut.name,
      description: cut.description,
      color: cut.color,
      opacity: parseFloat(String(cut.opacity)),
      category: cut.category,
      isPublic: cut.isPublic,
      isOfficial: cut.isOfficial,
      showLocations: cut.showLocations,
      exportEnabled: cut.exportEnabled,
      assignedTo: cut.assignedTo,
    });
    setEditDrawerOpen(true);
  };

  const handleFinishDraw = (geojson: string, bounds: string) => {
    setPendingGeojson(geojson);
    setPendingBounds(bounds);
    createForm.resetFields();
    createForm.setFieldsValue({ color: '#3388ff', opacity: 0.3 });
    setCreateDrawerOpen(true);
  };

  const columns: ColumnsType<Cut> = [
    {
      title: 'Name',
      dataIndex: 'name',
      key: 'name',
      render: (name: string) => <span style={{ fontWeight: 500 }}>{name}</span>,
    },
    {
      title: 'Color',
      dataIndex: 'color',
      key: 'color',
      width: 60,
      render: (color: string, record: Cut) => (
        <div
          style={{
            width: 24,
            height: 24,
            borderRadius: 4,
            backgroundColor: color,
            opacity: parseFloat(String(record.opacity)) || 0.3,
            border: `2px solid ${color}`,
          }}
        />
      ),
    },
    {
      title: 'Category',
      dataIndex: 'category',
      key: 'category',
      render: (cat: CutCategory | null) =>
        cat ? (
          <Tag color={CUT_CATEGORY_COLORS[cat]}>{CUT_CATEGORY_LABELS[cat]}</Tag>
        ) : (
          <Tag>None</Tag>
        ),
    },
    {
      title: 'Public',
      dataIndex: 'isPublic',
      key: 'isPublic',
      width: 80,
      render: (isPublic: boolean, record: Cut) => (
        <Switch
          checked={isPublic}
          size="small"
          onChange={async (checked) => {
            try {
              await api.put(`/map/cuts/${record.id}`, { isPublic: checked });
              fetchCuts();
            } catch {
              message.error('Failed to update');
            }
          }}
        />
      ),
    },
    {
      title: 'Assigned To',
      dataIndex: 'assignedTo',
      key: 'assignedTo',
      render: (val: string | null) => val || '--',
      responsive: ['lg'],
    },
    {
      title: 'Created',
      dataIndex: 'createdAt',
      key: 'createdAt',
      render: (date: string) => dayjs(date).format('YYYY-MM-DD'),
      responsive: ['xl'],
    },
    {
      title: 'Actions',
      key: 'actions',
      width: 150,
      render: (_: unknown, record: Cut) => (
        <Space>
          <Button
            type="link"
            size="small"
            icon={<DownloadOutlined />}
            onClick={(e) => { e.stopPropagation(); handleExportSingle(record.id, record.name); }}
            title="Download GeoJSON"
          />
          <Button
            type="link"
            size="small"
            icon={<PrinterOutlined />}
            onClick={(e) => { e.stopPropagation(); navigate(`/app/map/cuts/${record.id}/export`); }}
            title="Export"
          />
          <Button
            type="link"
            size="small"
            icon={<EditOutlined />}
            onClick={() => openEdit(record)}
            title="Edit"
          />
          <Popconfirm
            title="Delete this cut?"
            onConfirm={() => handleDelete(record.id)}
          >
            <Button type="link" size="small" danger icon={<DeleteOutlined />} title="Delete" />
          </Popconfirm>
        </Space>
      ),
    },
  ];

  const cutFormFields = (
    <>
      <Form.Item
        name="name"
        label="Name"
        rules={[{ required: true, message: 'Name is required' }]}
      >
        <Input />
      </Form.Item>
      <Form.Item name="description" label="Description">
        <Input.TextArea rows={2} />
      </Form.Item>
      <Row gutter={12}>
        <Col span={8}>
          <Form.Item name="color" label="Color">
            <Input type="color" style={{ width: 60, padding: 2, cursor: 'pointer' }} />
          </Form.Item>
        </Col>
        <Col span={16}>
          <Form.Item name="opacity" label="Opacity">
            <Slider min={0} max={1} step={0.05} />
          </Form.Item>
        </Col>
      </Row>
      <Form.Item name="category" label="Category">
        <Select options={categoryOptions} allowClear placeholder="Select category" />
      </Form.Item>
      <Row gutter={12}>
        <Col span={8}>
          <Form.Item name="isPublic" label="Public" valuePropName="checked">
            <Switch />
          </Form.Item>
        </Col>
        <Col span={8}>
          <Form.Item name="isOfficial" label="Official" valuePropName="checked">
            <Switch />
          </Form.Item>
        </Col>
        <Col span={8}>
          <Form.Item name="showLocations" label="Show Locations" valuePropName="checked">
            <Switch />
          </Form.Item>
        </Col>
      </Row>
      <Form.Item name="assignedTo" label="Assigned To">
        <Input placeholder="e.g. Volunteer name" />
      </Form.Item>
    </>
  );

  const { setPageHeader } = useOutletContext<AppOutletContext>();

  useEffect(() => {
    setPageHeader({
      title: 'Cuts',
      fullBleed: activeTab === 'map'
    });
    return () => setPageHeader(null);
  }, [setPageHeader, activeTab]);

  const anyDrawerOpen = createDrawerOpen || importDrawerOpen || editDrawerOpen;
  const activeDrawerWidth = isMobile ? 0 : (createDrawerOpen ? 500 : importDrawerOpen ? 500 : editDrawerOpen ? 480 : 0);

  return (
    <>
      <div style={{ marginRight: anyDrawerOpen ? activeDrawerWidth : 0, transition: 'margin-right 0.15s cubic-bezier(0.2, 0, 0, 1)' }}>
        {/* Action bar */}
        <Row justify="space-between" align="middle" style={{ marginBottom: 16 }}>
          <Segmented
            value={activeTab}
            onChange={(val) => setActiveTab(val as string)}
            options={[
              { value: 'table', icon: <TableOutlined />, label: 'Table' },
              { value: 'map', icon: <EnvironmentOutlined />, label: 'Map' },
            ]}
            size="middle"
          />
          <Space>
            <Button icon={<ExportOutlined />} onClick={handleExportAll}>Export GeoJSON</Button>
            <Button icon={<ImportOutlined />} onClick={() => setImportDrawerOpen(true)}>Import GeoJSON</Button>
            <Button type="primary" icon={<PlusOutlined />} onClick={() => setActiveTab('map')}>Draw New Cut</Button>
          </Space>
        </Row>

        {activeTab === 'table' ? (
          <>
            <Row gutter={[12, 12]} style={{ marginBottom: 16 }}>
              <Col xs={24} sm={12} md={8}>
                <Input
                  placeholder="Search name or description"
                  prefix={<SearchOutlined />}
                  value={search}
                  onChange={(e) => handleSearchChange(e.target.value)}
                  allowClear
                />
              </Col>
              <Col xs={12} sm={6} md={4}>
                <Select
                  placeholder="Category"
                  options={categoryOptions}
                  value={categoryFilter}
                  onChange={setCategoryFilter}
                  allowClear
                  style={{ width: '100%' }}
                />
              </Col>
            </Row>

            <Table<Cut>
              columns={columns}
              dataSource={cuts}
              rowKey="id"
              loading={loading}
              scroll={{ x: 'max-content' }}
              pagination={{
                current: pagination.page,
                pageSize: pagination.limit,
                total: pagination.total,
                showSizeChanger: true,
                showTotal: (total) => `${total} cuts`,
              }}
              onChange={handleTableChange}
              onRow={(record) => ({
                onClick: () => openEdit(record),
                style: { cursor: 'pointer' },
              })}
            />
          </>
        ) : isMobile ? (
          <Result
            status="warning"
            title="Desktop Required"
            subTitle="Cut drawing requires a mouse for precise polygon editing. Please use a desktop browser for the map editor. The table view above is fully usable on mobile."
            extra={
              <Button type="primary" onClick={() => setActiveTab('table')}>
                Switch to Table
              </Button>
            }
          />
        ) : (
          <CutEditorMap
            cuts={cuts}
            onFinishDraw={handleFinishDraw}
          />
        )}
      </div>

      {/* Create Drawer */}
      <Drawer
        title="Create Cut"
        open={createDrawerOpen}
        destroyOnHidden
        mask={false}
        width={isMobile ? '100%' : 500}
        rootStyle={{ position: 'absolute', top: 64, height: 'calc(100vh - 64px)' }}
        onClose={() => {
          setCreateDrawerOpen(false);
          createForm.resetFields();
          setPendingGeojson(null);
          setPendingBounds(null);
        }}
        extra={
          <Space>
            <Button onClick={() => { setCreateDrawerOpen(false); createForm.resetFields(); setPendingGeojson(null); setPendingBounds(null); }}>
              Cancel
            </Button>
            <Button type="primary" onClick={() => createForm.submit()}>
              Create
            </Button>
          </Space>
        }
      >
        <Form
          form={createForm}
          onFinish={handleCreate}
          layout="vertical"
          initialValues={{ color: '#3388ff', opacity: 0.3 }}
        >
          {cutFormFields}
        </Form>
      </Drawer>

      {/* Import GeoJSON Drawer */}
      <Drawer
        title="Import GeoJSON"
        open={importDrawerOpen}
        destroyOnHidden
        mask={false}
        width={isMobile ? '100%' : 500}
        rootStyle={{ position: 'absolute', top: 64, height: 'calc(100vh - 64px)' }}
        onClose={() => setImportDrawerOpen(false)}
        extra={
          <Button onClick={() => setImportDrawerOpen(false)}>
            Close
          </Button>
        }
      >
        <Typography.Paragraph type="secondary">
          Upload a GeoJSON file containing Polygon or MultiPolygon features.
          Supported formats: Feature, FeatureCollection, or bare Polygon/MultiPolygon.
          Properties like name, color, fill-opacity, and category will be mapped automatically.
        </Typography.Paragraph>
        <Upload.Dragger
          accept=".geojson,.json"
          maxCount={1}
          showUploadList={false}
          customRequest={({ file }) => handleImport(file as File)}
          disabled={importing}
        >
          <p style={{ fontSize: 32, color: '#1890ff' }}>
            <UploadOutlined />
          </p>
          <p>{importing ? 'Importing...' : 'Click or drag a .geojson file here'}</p>
        </Upload.Dragger>
      </Drawer>

      {/* Edit Drawer */}
      <Drawer
        title="Edit Cut"
        open={editDrawerOpen}
        destroyOnHidden
        mask={false}
        width={isMobile ? '100%' : 480}
        rootStyle={{ position: 'absolute', top: 64, height: 'calc(100vh - 64px)' }}
        onClose={() => {
          setEditDrawerOpen(false);
          setEditingCut(null);
          editForm.resetFields();
        }}
        extra={
          <Space>
            <Button onClick={() => { setEditDrawerOpen(false); setEditingCut(null); editForm.resetFields(); }}>
              Cancel
            </Button>
            <Button type="primary" onClick={() => editForm.submit()}>
              Save
            </Button>
          </Space>
        }
      >
        <Form form={editForm} onFinish={handleEdit} layout="vertical">
          {cutFormFields}
        </Form>
      </Drawer>
    </>
  );
}
