import { Button, Card, Descriptions, Empty, Flex, Input, List, Space, Spin, Table, Tag, Typography, message } from 'antd';
import { useEffect, useMemo, useState } from 'react';
import { useTokenAccess } from '../../app/main/tokenAccess';
import { fetchVisitorClients, fetchVisitorDetail, updateVisitorNickname, type VisitorClientSearchFilters } from './api';
import type { VisitHistory, VisitorClient } from './types';

const { Paragraph, Text, Title } = Typography;

function formatDateTime(value: string | null | undefined) {
  if (!value) {
    return '미기록';
  }

  return new Date(value).toLocaleString('ko-KR', {
    timeZone: 'Asia/Seoul',
  });
}

function formatCompactText(value: string | null | undefined) {
  if (!value) {
    return '-';
  }

  return value.length > 88 ? `${value.slice(0, 85)}...` : value;
}

function normalizeVisitorFilters(filters: VisitorClientSearchFilters) {
  return Object.fromEntries(
    Object.entries(filters)
      .map(([key, value]) => [key, value?.trim() ?? ''])
      .filter(([, value]) => Boolean(value)),
  ) as VisitorClientSearchFilters;
}

export function HistoryPage() {
  const { hasAccess } = useTokenAccess();
  const [messageApi, contextHolder] = message.useMessage();
  const [searchFilters, setSearchFilters] = useState<VisitorClientSearchFilters>({});
  const [filterInputs, setFilterInputs] = useState<VisitorClientSearchFilters>({});
  const [visitors, setVisitors] = useState<VisitorClient[]>([]);
  const [selectedClientId, setSelectedClientId] = useState<string | null>(null);
  const [selectedClient, setSelectedClient] = useState<VisitorClient | null>(null);
  const [visits, setVisits] = useState<VisitHistory[]>([]);
  const [nicknameInput, setNicknameInput] = useState('');
  const [loading, setLoading] = useState(false);
  const [detailLoading, setDetailLoading] = useState(false);
  const [savingNickname, setSavingNickname] = useState(false);
  const [errorMessage, setErrorMessage] = useState<string | null>(null);

  useEffect(() => {
    if (!hasAccess) {
      setVisitors([]);
      setSelectedClientId(null);
      setSelectedClient(null);
      setVisits([]);
      return;
    }

    let cancelled = false;

    const loadVisitors = async () => {
      setLoading(true);
      setErrorMessage(null);

      try {
        const nextVisitors = await fetchVisitorClients(searchFilters);

        if (cancelled) {
          return;
        }

        setVisitors(nextVisitors);
        setSelectedClientId((previous) => {
          if (previous && nextVisitors.some((item) => item.clientId === previous)) {
            return previous;
          }

          return nextVisitors[0]?.clientId ?? null;
        });
      } catch (error) {
        if (!cancelled) {
          setErrorMessage(error instanceof Error ? error.message : '방문자 목록을 불러오지 못했습니다.');
        }
      } finally {
        if (!cancelled) {
          setLoading(false);
        }
      }
    };

    void loadVisitors();

    return () => {
      cancelled = true;
    };
  }, [hasAccess, searchFilters]);

  useEffect(() => {
    if (!hasAccess || !selectedClientId) {
      setSelectedClient(null);
      setVisits([]);
      setNicknameInput('');
      return;
    }

    let cancelled = false;

    const loadDetail = async () => {
      setDetailLoading(true);

      try {
        const detail = await fetchVisitorDetail(selectedClientId);

        if (cancelled) {
          return;
        }

        setSelectedClient(detail.client);
        setVisits(detail.visits);
        setNicknameInput(detail.client.nickname);
      } catch (error) {
        if (!cancelled) {
          messageApi.error(error instanceof Error ? error.message : '방문 상세를 불러오지 못했습니다.');
          setSelectedClient(null);
          setVisits([]);
          setNicknameInput('');
        }
      } finally {
        if (!cancelled) {
          setDetailLoading(false);
        }
      }
    };

    void loadDetail();

    return () => {
      cancelled = true;
    };
  }, [hasAccess, messageApi, selectedClientId]);

  const visitColumns = useMemo(
    () => [
      {
        title: '방문시각',
        dataIndex: 'visitedAt',
        key: 'visitedAt',
        render: (value: string) => formatDateTime(value),
      },
      {
        title: '이벤트',
        dataIndex: 'eventType',
        key: 'eventType',
        render: (value: string) => <Tag color="blue">{value}</Tag>,
      },
      {
        title: 'URL',
        dataIndex: 'url',
        key: 'url',
        render: (value: string) => (
          <Typography.Link href={value} target="_blank" rel="noreferrer">
            {formatCompactText(value)}
          </Typography.Link>
        ),
      },
      {
        title: 'IP',
        dataIndex: 'ip',
        key: 'ip',
        render: (value: string | null) => value ?? '-',
      },
    ],
    [],
  );

  const handleSaveNickname = async () => {
    if (!selectedClientId) {
      return;
    }

    const normalizedNickname = nicknameInput.trim();

    if (!normalizedNickname) {
      messageApi.warning('닉네임을 입력해 주세요.');
      return;
    }

    setSavingNickname(true);

    try {
      const updatedClient = await updateVisitorNickname(selectedClientId, normalizedNickname);
      setSelectedClient(updatedClient);
      setNicknameInput(updatedClient.nickname);
      setVisitors((previous) =>
        previous.map((item) => (item.clientId === updatedClient.clientId ? updatedClient : item)),
      );
      messageApi.success('닉네임을 수정했습니다.');
    } catch (error) {
      messageApi.error(error instanceof Error ? error.message : '닉네임 수정에 실패했습니다.');
    } finally {
      setSavingNickname(false);
    }
  };

  if (!hasAccess) {
    return (
      <Card className="history-page__card" bordered={false}>
        <Paragraph className="app-main-copy">
          토큰 등록 사용자만 방문 이력 메뉴를 사용할 수 있습니다.
        </Paragraph>
      </Card>
    );
  }

  return (
    <Space direction="vertical" size={16} className="history-page">
      {contextHolder}
      <Card className="history-page__card" bordered={false}>
        <Flex justify="space-between" align="center" gap={16} wrap>
          <div>
            <Title level={4} className="history-page__title">
              방문자 이력
            </Title>
            <Paragraph className="history-page__copy">
              `client master / visit history` 구조로 비로그인 방문자를 식별하고 상세 이력을 조회합니다.
            </Paragraph>
          </div>
        </Flex>
        <div className="history-page__filter-grid">
          <Input
            allowClear
            placeholder="clientId"
            value={filterInputs.clientId}
            onChange={(event) => {
              setFilterInputs((previous) => ({ ...previous, clientId: event.target.value }));
            }}
          />
          <Input
            allowClear
            placeholder="닉네임"
            value={filterInputs.nickname}
            onChange={(event) => {
              setFilterInputs((previous) => ({ ...previous, nickname: event.target.value }));
            }}
          />
          <Input
            allowClear
            placeholder="방문 경로"
            value={filterInputs.path}
            onChange={(event) => {
              setFilterInputs((previous) => ({ ...previous, path: event.target.value }));
            }}
          />
          <Input
            allowClear
            placeholder="시작일 YYYY-MM-DD"
            value={filterInputs.visitedFrom}
            onChange={(event) => {
              setFilterInputs((previous) => ({ ...previous, visitedFrom: event.target.value }));
            }}
          />
          <Input
            allowClear
            placeholder="종료일 YYYY-MM-DD"
            value={filterInputs.visitedTo}
            onChange={(event) => {
              setFilterInputs((previous) => ({ ...previous, visitedTo: event.target.value }));
            }}
          />
          <Space>
            <Button
              type="primary"
              onClick={() => {
                setSearchFilters(normalizeVisitorFilters(filterInputs));
              }}
            >
              검색
            </Button>
            <Button
              onClick={() => {
                setFilterInputs({});
                setSearchFilters({});
              }}
            >
              초기화
            </Button>
          </Space>
        </div>
      </Card>

      {errorMessage ? (
        <Card className="history-page__card" bordered={false}>
          <Text type="danger">{errorMessage}</Text>
        </Card>
      ) : null}

      <div className="history-page__grid">
        <Card
          title={`전체 방문자 목록 (${visitors.length})`}
          className="history-page__card history-page__list-card"
          extra={loading ? <Spin size="small" /> : null}
          bordered={false}
        >
          {loading ? (
            <div className="history-page__loading">
              <Spin />
            </div>
          ) : visitors.length ? (
            <List
              dataSource={visitors}
              renderItem={(item) => (
                <List.Item
                  className={item.clientId === selectedClientId ? 'history-page__list-item is-active' : 'history-page__list-item'}
                  onClick={() => {
                    setSelectedClientId(item.clientId);
                  }}
                >
                  <Space direction="vertical" size={4}>
                    <Text strong>{item.nickname}</Text>
                    <Text type="secondary">{item.clientId}</Text>
                    <Text type="secondary">누적 방문 {item.visitCount}회</Text>
                    <Text type="secondary">최근 방문 {formatDateTime(item.lastVisitedAt)}</Text>
                  </Space>
                </List.Item>
              )}
            />
          ) : (
            <Empty description="조회된 방문자가 없습니다." />
          )}
        </Card>

        <Card
          title="특정 clientId 상세 조회"
          className="history-page__card history-page__detail-card"
          extra={detailLoading ? <Spin size="small" /> : null}
          bordered={false}
        >
          {!selectedClientId ? (
            <Empty description="방문자를 선택해 주세요." />
          ) : detailLoading && !selectedClient ? (
            <div className="history-page__loading">
              <Spin />
            </div>
          ) : selectedClient ? (
            <Space direction="vertical" size={16} className="history-page__detail">
              <Descriptions
                column={1}
                size="small"
                items={[
                  { key: 'clientId', label: 'clientId', children: selectedClient.clientId },
                  { key: 'firstVisitedAt', label: '최초 방문', children: formatDateTime(selectedClient.firstVisitedAt) },
                  { key: 'lastVisitedAt', label: '최근 방문', children: formatDateTime(selectedClient.lastVisitedAt) },
                  { key: 'visitCount', label: '방문 수', children: `${selectedClient.visitCount}회` },
                  {
                    key: 'lastVisitedUrl',
                    label: '최근 URL',
                    children: selectedClient.lastVisitedUrl ? (
                      <Typography.Link href={selectedClient.lastVisitedUrl} target="_blank" rel="noreferrer">
                        {formatCompactText(selectedClient.lastVisitedUrl)}
                      </Typography.Link>
                    ) : (
                      '-'
                    ),
                  },
                  { key: 'lastUserAgent', label: 'User-Agent', children: formatCompactText(selectedClient.lastUserAgent) },
                  { key: 'lastIp', label: 'IP', children: selectedClient.lastIp ?? '-' },
                ]}
              />

              <Flex gap={8} wrap>
                <Input
                  value={nicknameInput}
                  onChange={(event) => {
                    setNicknameInput(event.target.value);
                  }}
                  placeholder="닉네임 수정"
                />
                <Button type="primary" onClick={handleSaveNickname} loading={savingNickname}>
                  닉네임 수정
                </Button>
              </Flex>

              <Table<VisitHistory>
                rowKey="id"
                columns={visitColumns}
                dataSource={visits}
                pagination={{ pageSize: 8, showSizeChanger: false }}
                scroll={{ x: 720 }}
              />
            </Space>
          ) : (
            <Empty description="방문 상세를 불러오지 못했습니다." />
          )}
        </Card>
      </div>
    </Space>
  );
}
