import {
  ControlOutlined,
  DatabaseOutlined,
  DeleteOutlined,
  EditOutlined,
  PlusOutlined,
  RightOutlined,
  UploadOutlined,
  WarningOutlined,
} from '@ant-design/icons'
import {
  Alert,
  AutoComplete,
  Button,
  Checkbox,
  Col,
  Collapse,
  Segmented,
  Divider,
  Form,
  Input,
  InputNumber,
  Modal,
  Popconfirm,
  Row,
  Space,
  Table,
  Tag,
  Typography,
  Upload,
  message,
} from 'antd'
import dayjs from 'dayjs'
import { useMemo, useState } from 'react'
import { useNavigate } from 'react-router-dom'
import {
  useCreateObject,
  useDeleteObject,
  useObjectsMeta,
  useUpdateObject,
  useObjects,
  usePreviewObjectsXLSX,
  useImportObjectsXLSX,
  type ObjectItem,
  type ObjectImportPreview,
} from '../api/objects'
import { stripEmpty } from '../utils/form'

interface Props {
  mode: 'inventory' | 'work'
}

const UNGROUPED = '__none__'

export function ObjectsPage({ mode }: Props) {
  const navigate = useNavigate()
  const { data: objects, isLoading } = useObjects()
  const { data: meta } = useObjectsMeta()
  const createObject = useCreateObject()
  const updateObject = useUpdateObject()
  const deleteObject = useDeleteObject()

  const [modalOpen, setModalOpen] = useState(false)
  const [editTarget, setEditTarget] = useState<ObjectItem | null>(null)
  const [searchText, setSearchText] = useState('')
  const [form] = Form.useForm()

  // Import modal state
  const [importOpen, setImportOpen] = useState(false)
  const [importFile, setImportFile] = useState<File | null>(null)
  const [importPreview, setImportPreview] = useState<ObjectImportPreview | null>(null)
  const [importStep, setImportStep] = useState<'upload' | 'preview'>('upload')
  const previewMutation = usePreviewObjectsXLSX()
  const importMutation = useImportObjectsXLSX()

  const objectUrl = (id: number) =>
    mode === 'inventory' ? `/inventory/objects/${id}` : `/work/objects/${id}`

  const filteredObjects = useMemo(() => {
    if (!searchText) return objects ?? []
    const q = searchText.toLowerCase()
    return (objects ?? []).filter(
      (o) =>
        o.name.toLowerCase().includes(q) ||
        (o.city ?? '').toLowerCase().includes(q) ||
        (o.client ?? '').toLowerCase().includes(q)
    )
  }, [objects, searchText])

  // Group: city → objects[]. Null city → UNGROUPED key
  const cityGroups = useMemo(() => {
    const map = new Map<string, ObjectItem[]>()
    for (const obj of filteredObjects) {
      const key = obj.city ?? UNGROUPED
      if (!map.has(key)) map.set(key, [])
      map.get(key)!.push(obj)
    }
    // Sort: named cities first (alphabetical), ungrouped last
    const sorted = [...map.entries()].sort(([a], [b]) => {
      if (a === UNGROUPED) return 1
      if (b === UNGROUPED) return -1
      return a.localeCompare(b, 'ru')
    })
    return sorted
  }, [filteredObjects])

  const openCreate = () => {
    form.resetFields()
    setEditTarget(null)
    setModalOpen(true)
  }

  const openEdit = (row: ObjectItem) => {
    form.resetFields()
    form.setFieldsValue({
      name: row.name,
      description: row.description ?? '',
      server_ip: row.server_ip ?? '',
      city: row.city ?? '',
      client: row.client ?? '',
      ssh_user: row.ssh_user ?? '',
      db_host: row.db_host ?? '',
    })
    setEditTarget(row)
    setModalOpen(true)
  }

  const handleSubmit = async () => {
    const values = await form.validateFields()
    const payload = stripEmpty(values)
    try {
      if (editTarget === null) {
        await createObject.mutateAsync(payload as any)
        message.success('Объект создан')
      } else {
        await updateObject.mutateAsync({ id: editTarget.id, body: payload as any })
        message.success('Объект обновлён')
      }
      setModalOpen(false)
      form.resetFields()
    } catch {
      message.error(editTarget === null ? 'Ошибка при создании' : 'Ошибка при обновлении')
    }
  }

  const handleDelete = async (row: ObjectItem) => {
    try {
      await deleteObject.mutateAsync(row.id)
      message.success(`Объект "${row.name}" удалён`)
    } catch (err: any) {
      if (err?.response?.status === 409) {
        message.error('Нельзя удалить объект с устройствами')
      } else {
        message.error(err?.response?.data?.detail ?? 'Ошибка при удалении')
      }
    }
  }

  const isSubmitting = createObject.isPending || updateObject.isPending

  const openImport = () => {
    setImportFile(null)
    setImportPreview(null)
    setImportStep('upload')
    setImportOpen(true)
  }

  const handleImportFileChange = async (file: File) => {
    setImportFile(file)
    setImportPreview(null)
    try {
      const preview = await previewMutation.mutateAsync(file)
      setImportPreview(preview)
      setImportStep('preview')
    } catch {
      message.error('Не удалось прочитать файл')
    }
  }

  const handleImportConfirm = async () => {
    if (!importFile) return
    try {
      const result = await importMutation.mutateAsync(importFile)
      setImportOpen(false)
      message.success(
        `Импорт завершён: создано ${result.created}, пропущено ${result.skipped}` +
          (result.errors.length ? `, ошибок ${result.errors.length}` : '')
      )
    } catch {
      message.error('Ошибка при импорте')
    }
  }

  const renderObjectRow = (obj: ObjectItem) => (
    <div
      key={obj.id}
      style={{
        display: 'flex',
        alignItems: 'center',
        padding: '8px 16px',
        borderBottom: '1px solid #f0f0f0',
        gap: 12,
      }}
    >
      <Button
        type="link"
        style={{ padding: 0, fontWeight: 500, flex: 1, textAlign: 'left', justifyContent: 'flex-start' }}
        onClick={() => navigate(objectUrl(obj.id))}
      >
        <RightOutlined style={{ fontSize: 11, marginRight: 6, color: '#999' }} />
        {obj.name}
      </Button>
      {obj.client && <Typography.Text type="secondary" style={{ fontSize: 12 }}>{obj.client}</Typography.Text>}
      {obj.server_ip && <Typography.Text code style={{ fontSize: 12 }}>{obj.server_ip}</Typography.Text>}
      {obj.tags.map((t) => (
        <Tag key={t.id} color={t.color} style={{ margin: 0 }}>{t.name}</Tag>
      ))}
      {!obj.is_active && <Tag color="default">Неактивен</Tag>}
      <Typography.Text type="secondary" style={{ fontSize: 12, whiteSpace: 'nowrap' }}>
        {obj.device_count} уст.
      </Typography.Text>
      <Typography.Text type="secondary" style={{ fontSize: 12, whiteSpace: 'nowrap' }}>
        изм. {dayjs(obj.updated_at).format('DD.MM.YY HH:mm')}
      </Typography.Text>
      {mode === 'inventory' && (
        <Space size={4}>
          <Button size="small" icon={<EditOutlined />} onClick={() => openEdit(obj)} />
          <Popconfirm
            title="Удалить объект?"
            description="Объект можно удалить только если у него нет устройств."
            okText="Удалить"
            cancelText="Отмена"
            okButtonProps={{ danger: true }}
            onConfirm={() => handleDelete(obj)}
          >
            <Button size="small" danger icon={<DeleteOutlined />} loading={deleteObject.isPending} />
          </Popconfirm>
        </Space>
      )}
    </div>
  )

  const collapseItems = cityGroups.map(([city, objs]) => ({
    key: city,
    label: (
      <Space>
        <Typography.Text strong>{city === UNGROUPED ? 'Без города' : city}</Typography.Text>
        <Tag>{objs.length}</Tag>
      </Space>
    ),
    children: (
      <div style={{ margin: '-12px -16px' }}>
        {objs.map(renderObjectRow)}
      </div>
    ),
  }))

  return (
    <div>
      <div
        style={{
          display: 'flex',
          justifyContent: 'space-between',
          alignItems: 'center',
          marginBottom: 16,
        }}
      >
        <Space align="center" size={16}>
          <Typography.Title level={4} style={{ margin: 0 }}>
            {mode === 'inventory' ? 'Инвентарь — Объекты' : 'Работа — Объекты'}
          </Typography.Title>
          <Segmented
            value={mode}
            options={[
              { label: 'Инвентарь', value: 'inventory', icon: <DatabaseOutlined /> },
              { label: 'Работа',    value: 'work',      icon: <ControlOutlined /> },
            ]}
            onChange={(val) => navigate(val === 'inventory' ? '/inventory/objects' : '/work/objects')}
          />
        </Space>
        <Space>
          <Input.Search
            placeholder="Поиск по названию, городу, клиенту..."
            allowClear
            style={{ width: 300 }}
            onChange={(e) => setSearchText(e.target.value)}
          />
          {mode === 'inventory' && (
            <Space>
              <Button icon={<UploadOutlined />} onClick={openImport}>
                Импортировать xlsx
              </Button>
              <Button type="primary" icon={<PlusOutlined />} onClick={openCreate}>
                Добавить
              </Button>
            </Space>
          )}
        </Space>
      </div>

      {isLoading ? (
        <Typography.Text type="secondary">Загрузка...</Typography.Text>
      ) : cityGroups.length === 0 ? (
        <Typography.Text type="secondary">Нет объектов</Typography.Text>
      ) : (
        <Collapse
          defaultActiveKey={cityGroups.map(([city]) => city)}
          items={collapseItems}
        />
      )}

      {/* Import xlsx modal */}
      <Modal
        title="Импорт объектов из xlsx"
        open={importOpen}
        onCancel={() => setImportOpen(false)}
        width={900}
        footer={
          importStep === 'preview' && importPreview
            ? [
                <Button key="back" onClick={() => setImportStep('upload')}>
                  Назад
                </Button>,
                <Button
                  key="confirm"
                  type="primary"
                  loading={importMutation.isPending}
                  disabled={importPreview.would_create.length === 0}
                  onClick={handleImportConfirm}
                >
                  Создать {importPreview.would_create.length} объектов
                </Button>,
              ]
            : null
        }
      >
        {importStep === 'upload' && (
          <div style={{ textAlign: 'center', padding: '32px 0' }}>
            <Upload.Dragger
              accept=".xlsx"
              showUploadList={false}
              beforeUpload={(file) => {
                handleImportFileChange(file)
                return false
              }}
              style={{ padding: '16px 32px' }}
            >
              <p className="ant-upload-drag-icon">
                <UploadOutlined style={{ fontSize: 48, color: '#1677ff' }} />
              </p>
              <p className="ant-upload-text">Перетащите .xlsx файл или нажмите для выбора</p>
              <p className="ant-upload-hint" style={{ color: '#999' }}>
                Поддерживается шаблон objects_import_template.xlsx
              </p>
            </Upload.Dragger>
            {previewMutation.isPending && (
              <Typography.Text type="secondary" style={{ marginTop: 12, display: 'block' }}>
                Анализируем файл...
              </Typography.Text>
            )}
          </div>
        )}

        {importStep === 'preview' && importPreview && (
          <div>
            {/* Summary */}
            <Space style={{ marginBottom: 16, flexWrap: 'wrap' }}>
              <Tag color="green" style={{ fontSize: 13, padding: '2px 10px' }}>
                Будет создано: {importPreview.would_create.length}
              </Tag>
              {importPreview.would_skip.length > 0 && (
                <Tag color="orange" style={{ fontSize: 13, padding: '2px 10px' }}>
                  Пропущено (дубли): {importPreview.would_skip.length}
                </Tag>
              )}
              {importPreview.errors.length > 0 && (
                <Tag color="red" style={{ fontSize: 13, padding: '2px 10px' }}>
                  Ошибок: {importPreview.errors.length}
                </Tag>
              )}
            </Space>

            {/* Would create table */}
            {importPreview.would_create.length > 0 && (
              <>
                <Typography.Text strong>Будет создано</Typography.Text>
                <Table
                  size="small"
                  style={{ marginTop: 8, marginBottom: 16 }}
                  dataSource={importPreview.would_create}
                  rowKey="row"
                  pagination={{ pageSize: 10, hideOnSinglePage: true }}
                  columns={[
                    { title: '#', dataIndex: 'row', width: 50 },
                    { title: 'Название', dataIndex: 'name' },
                    { title: 'Город', dataIndex: 'city', width: 130 },
                    {
                      title: 'IP сервера',
                      dataIndex: 'server_ip',
                      width: 140,
                      render: (v: string) => <Typography.Text code>{v}</Typography.Text>,
                    },
                    { title: 'Клиент', dataIndex: 'client', width: 130, render: (v) => v ?? '—' },
                    {
                      title: 'SSH',
                      dataIndex: 'ssh_user',
                      width: 80,
                      render: (v: string) => <Typography.Text type="secondary">{v}</Typography.Text>,
                    },
                  ]}
                />
              </>
            )}

            {/* Skipped */}
            {importPreview.would_skip.length > 0 && (
              <>
                <Typography.Text strong>
                  <WarningOutlined style={{ color: '#fa8c16', marginRight: 6 }} />
                  Пропущены (дубликаты по IP)
                </Typography.Text>
                <Table
                  size="small"
                  style={{ marginTop: 8, marginBottom: 16 }}
                  dataSource={importPreview.would_skip}
                  rowKey="row"
                  pagination={{ pageSize: 5, hideOnSinglePage: true }}
                  columns={[
                    { title: '#', dataIndex: 'row', width: 50 },
                    { title: 'Название', dataIndex: 'name' },
                    {
                      title: 'IP',
                      dataIndex: 'server_ip',
                      width: 140,
                      render: (v: string) => <Typography.Text code>{v}</Typography.Text>,
                    },
                    { title: 'Причина', dataIndex: 'reason' },
                  ]}
                />
              </>
            )}

            {/* Errors */}
            {importPreview.errors.length > 0 && (
              <>
                <Alert
                  type="error"
                  showIcon
                  style={{ marginBottom: 8 }}
                  message={`${importPreview.errors.length} строк с ошибками будут пропущены`}
                />
                <Table
                  size="small"
                  style={{ marginBottom: 8 }}
                  dataSource={importPreview.errors}
                  rowKey="row"
                  pagination={{ pageSize: 5, hideOnSinglePage: true }}
                  columns={[
                    { title: '#', dataIndex: 'row', width: 50 },
                    { title: 'Ошибка', dataIndex: 'reason' },
                  ]}
                />
              </>
            )}
          </div>
        )}
      </Modal>

      {/* Create / Edit modal — only relevant in inventory mode */}
      <Modal
        title={editTarget === null ? 'Новый объект' : `Редактировать: ${editTarget.name}`}
        open={modalOpen}
        onCancel={() => { setModalOpen(false); form.resetFields() }}
        onOk={handleSubmit}
        confirmLoading={isSubmitting}
        okText={editTarget === null ? 'Создать' : 'Сохранить'}
        width={680}
      >
        <Form form={form} layout="vertical" style={{ marginTop: 16 }}>
          <Row gutter={16}>
            <Col span={14}>
              <Form.Item name="name" label="Название" rules={[{ required: true, message: 'Обязательное поле' }]}>
                <Input placeholder="Анапа, Парковка ТЦ Мира" />
              </Form.Item>
            </Col>
            <Col span={10}>
              <Form.Item name="server_ip" label="IP сервера объекта">
                <Input placeholder="10.23.0.201" />
              </Form.Item>
            </Col>
          </Row>

          <Row gutter={16}>
            <Col span={12}>
              <Form.Item name="city" label="Город">
                <AutoComplete
                  options={(meta?.cities ?? []).map((c) => ({ value: c }))}
                  filterOption={(input, opt) =>
                    (opt?.value ?? '').toLowerCase().includes(input.toLowerCase())
                  }
                  placeholder="Санкт-Петербург"
                />
              </Form.Item>
            </Col>
            <Col span={12}>
              <Form.Item name="client" label="Клиент">
                <AutoComplete
                  options={(meta?.clients ?? []).map((c) => ({ value: c }))}
                  filterOption={(input, opt) =>
                    (opt?.value ?? '').toLowerCase().includes(input.toLowerCase())
                  }
                  placeholder="Авангард"
                />
              </Form.Item>
            </Col>
          </Row>

          <Form.Item name="description" label="Описание">
            <Input.TextArea rows={2} />
          </Form.Item>

          <Divider orientation="left" plain>SSH (по умолчанию для устройств)</Divider>

          <Row gutter={16}>
            <Col span={8}>
              <Form.Item name="ssh_user" label="Логин">
                <Input placeholder="caps" />
              </Form.Item>
            </Col>
            <Col span={10}>
              <Form.Item name="ssh_password" label={editTarget ? 'Новый пароль' : 'Пароль'}>
                <Input.Password placeholder={editTarget ? 'Оставьте пустым чтобы не менять' : '••••••••'} />
              </Form.Item>
            </Col>
            <Col span={6}>
              <Form.Item name="ssh_port" label="Порт" initialValue={22}>
                <InputNumber style={{ width: '100%' }} min={1} max={65535} />
              </Form.Item>
            </Col>
          </Row>

          <Divider orientation="left" plain>
            Подключение к БД объекта{' '}
            <Typography.Text type="secondary" style={{ fontWeight: 400 }}>
              (для синхронизации)
            </Typography.Text>
          </Divider>

          <Row gutter={16}>
            <Col span={14}>
              <Form.Item name="db_host" label="Хост БД">
                <Input placeholder="10.23.0.202" />
              </Form.Item>
            </Col>
            <Col span={10}>
              <Form.Item name="db_port" label="Порт" initialValue={5432}>
                <InputNumber style={{ width: '100%' }} min={1} max={65535} />
              </Form.Item>
            </Col>
          </Row>

          <Row gutter={16}>
            <Col span={8}>
              <Form.Item name="db_name" label="База данных">
                <Input placeholder="caps" />
              </Form.Item>
            </Col>
            <Col span={8}>
              <Form.Item name="db_user" label="Пользователь">
                <Input placeholder="caps" />
              </Form.Item>
            </Col>
            <Col span={8}>
              <Form.Item name="db_password" label={editTarget ? 'Новый пароль' : 'Пароль'}>
                <Input.Password placeholder={editTarget ? 'Оставьте пустым чтобы не менять' : '••••••••'} />
              </Form.Item>
            </Col>
          </Row>

          <Row gutter={16}>
            <Col span={8}>
              <Form.Item name="db_table" label="Таблица">
                <Input placeholder="racks" />
              </Form.Item>
            </Col>
            <Col span={8}>
              <Form.Item name="db_col_ip" label="Колонка IP">
                <Input placeholder="ip_address" />
              </Form.Item>
            </Col>
            <Col span={8}>
              <Form.Item name="db_col_type" label="Колонка типа">
                <Input placeholder="device_type" />
              </Form.Item>
            </Col>
          </Row>

          <Form.Item name="db_via_tunnel" valuePropName="checked">
            <Checkbox>Подключаться через SSH-туннель</Checkbox>
          </Form.Item>
        </Form>
      </Modal>
    </div>
  )
}
