import {
  CreditCardOutlined,
  DeploymentUnitOutlined,
  ReloadOutlined,
  SearchOutlined,
  WalletOutlined
} from '@ant-design/icons';
import {
  Alert,
  Button,
  Card,
  Descriptions,
  Empty,
  Form,
  Input,
  InputNumber,
  Layout,
  Menu,
  Result,
  Space,
  Spin,
  Table,
  Tag,
  Typography
} from 'antd';
import { type ReactNode, useMemo, useState } from 'react';
import { BrowserRouter, Navigate, Route, Routes, useLocation, useNavigate } from 'react-router-dom';
import { ApiError } from './api/client';
import {
  capturePosPayment,
  loadDashboard,
  loadRecentPayments,
  loadTransactionDetail,
  type CapturePosPaymentRequest,
  type CapturePosPaymentResponse,
  type PosPaymentActivity,
  type PosTransactionDetailResponse,
  type PosTransactionSummaryResponse,
  type RecentPosPaymentsResponse
} from './api/dashboardApi';
import type { IdentityProvider } from './api/sessionApi';
import { buildGoogleOidcStartUrl } from './auth/oidcLogin';
import { SessionProvider, useSessionContext } from './auth/sessionContext';

type AppRoute = '/summary' | '/payments' | '/session';

type WorkflowState = {
  error: string | null;
  sessionExpired: boolean;
};

type PaymentAttempt = {
  request: CapturePosPaymentRequest;
  response: CapturePosPaymentResponse;
};

const routeItems: Array<{ key: AppRoute; label: string; icon: ReactNode }> = [
  { key: '/summary', label: 'Transaction Summary', icon: <WalletOutlined /> },
  { key: '/payments', label: 'Capture Payment', icon: <CreditCardOutlined /> },
  { key: '/session', label: 'Session', icon: <DeploymentUnitOutlined /> }
];

const paymentColumns = [
  { title: 'Transaction Id', dataIndex: 'transactionId' },
  { title: 'Method', dataIndex: 'paymentMethod' },
  { title: 'Amount', render: (_: unknown, record: PosPaymentActivity) => `${record.amount.toFixed(2)} ${record.currency}` },
  {
    title: 'Status',
    render: (_: unknown, record: PosPaymentActivity) => (
      <Tag color={paymentStatusColor(record.status)}>{record.status}</Tag>
    )
  },
  { title: 'Lifecycle Step', render: (_: unknown, record: PosPaymentActivity) => paymentProgressHint(record.status) },
  { title: 'Captured At', render: (_: unknown, record: PosPaymentActivity) => formatUtc(record.capturedAtUtc) }
];

function App() {
  return (
    <SessionProvider>
      <BrowserRouter>
        <PosTransactionsShell />
      </BrowserRouter>
    </SessionProvider>
  );
}

function PosTransactionsShell() {
  const session = useSessionContext();
  const location = useLocation();
  const navigate = useNavigate();

  const [contextId, setContextId] = useState('demo-context');
  const [transactionId, setTransactionId] = useState('POS-9001');
  const [summaryPayload, setSummaryPayload] = useState<PosTransactionSummaryResponse | null>(null);
  const [detailPayload, setDetailPayload] = useState<PosTransactionDetailResponse | null>(null);
  const [recentPayload, setRecentPayload] = useState<RecentPosPaymentsResponse | null>(null);
  const [paymentResponse, setPaymentResponse] = useState<CapturePosPaymentResponse | null>(null);
  const [paymentHistory, setPaymentHistory] = useState<PaymentAttempt[]>([]);
  const [lastCaptureRequest, setLastCaptureRequest] = useState<CapturePosPaymentRequest | null>(null);
  const [workflowState, setWorkflowState] = useState<WorkflowState>({ error: null, sessionExpired: false });
  const [loadingSummary, setLoadingSummary] = useState(false);
  const [loadingDetail, setLoadingDetail] = useState(false);
  const [loadingRecentPayments, setLoadingRecentPayments] = useState(false);
  const [submittingPayment, setSubmittingPayment] = useState(false);

  const loginUrl = useMemo(() => buildGoogleOidcStartUrl(window.location.href), []);
  const selectedKey = useMemo(() => {
    const candidate = routeItems.find((item) => location.pathname.startsWith(item.key));
    return candidate?.key ?? '/summary';
  }, [location.pathname]);

  const clearWorkflowError = () => setWorkflowState({ error: null, sessionExpired: false });

  const handleWorkflowFailure = async (err: unknown, fallbackMessage: string) => {
    if (err instanceof ApiError && err.status === 401) {
      setWorkflowState({ error: 'Your session expired. Sign in again to continue POS operations.', sessionExpired: true });
      await session.revalidate();
      return;
    }

    setWorkflowState({
      error: err instanceof Error ? err.message : fallbackMessage,
      sessionExpired: false
    });
  };

  const loadSummary = async () => {
    setLoadingSummary(true);
    clearWorkflowError();
    try {
      const payload = await loadDashboard(contextId);
      setSummaryPayload(payload);
    } catch (err) {
      await handleWorkflowFailure(err, 'Failed to load POS summary.');
    } finally {
      setLoadingSummary(false);
    }
  };

  const loadDetail = async () => {
    setLoadingDetail(true);
    clearWorkflowError();
    try {
      const payload = await loadTransactionDetail(contextId, transactionId);
      setDetailPayload(payload);
    } catch (err) {
      await handleWorkflowFailure(err, 'Failed to load transaction detail.');
    } finally {
      setLoadingDetail(false);
    }
  };

  const refreshRecentPayments = async () => {
    setLoadingRecentPayments(true);
    clearWorkflowError();
    try {
      const payload = await loadRecentPayments(contextId);
      setRecentPayload(payload);
    } catch (err) {
      await handleWorkflowFailure(err, 'Failed to load recent payments.');
    } finally {
      setLoadingRecentPayments(false);
    }
  };

  const submitCapturePayment = async (request: CapturePosPaymentRequest) => {
    setSubmittingPayment(true);
    clearWorkflowError();
    setLastCaptureRequest(request);

    try {
      const payload = await capturePosPayment(request);
      setPaymentResponse(payload);
      setPaymentHistory((previous) => [{ request, response: payload }, ...previous].slice(0, 8));
      await refreshRecentPayments();
      await loadSummary();
      await loadDetail();
    } catch (err) {
      await handleWorkflowFailure(err, 'Failed to capture payment.');
    } finally {
      setSubmittingPayment(false);
    }
  };

  if (session.status === 'loading') {
    return (
      <div className="fullscreen-center">
        <Spin size="large" />
      </div>
    );
  }

  if (session.status !== 'authenticated' || !session.profile) {
    return (
      <main className="app">
        <Result
          status="403"
          title="Authentication Required"
          subTitle="Sign in through the central auth host to access POS transaction workflows."
          extra={
            <Button type="primary" href={loginUrl}>
              Continue with Google
            </Button>
          }
        />
        {workflowState.sessionExpired && (
          <Alert
            type="warning"
            showIcon
            message="Session expired"
            description="Sign in again through the central auth host before retrying POS actions."
          />
        )}
        {session.error && <Alert type="error" showIcon message={session.error} />}
      </main>
    );
  }

  return (
    <Layout className="full-layout">
      <Layout.Sider width={240} breakpoint="lg" collapsedWidth={0}>
        <div className="brand">POS Transactions Web</div>
        <Menu mode="inline" selectedKeys={[selectedKey]} items={routeItems} onClick={(event) => navigate(event.key as AppRoute)} />
      </Layout.Sider>
      <Layout>
        <Layout.Header className="header">
          <Space wrap>
            <Tag color="blue">subject: {session.profile.subjectId}</Tag>
            <Tag color="geekblue">tenant: {session.profile.tenantId}</Tag>
            <Tag color="purple">provider: {providerLabel(session.profile.provider)}</Tag>
          </Space>
          <Space>
            <Button icon={<ReloadOutlined />} onClick={() => void session.refresh()}>
              Refresh Session
            </Button>
            <Button danger onClick={() => void session.logout()}>
              Logout
            </Button>
          </Space>
        </Layout.Header>
        <Layout.Content className="content">
          <Typography.Title level={3}>POS Transactions</Typography.Title>
          <Typography.Paragraph type="secondary">
            Protected POS workflows for payable restaurant checks, capture retries, and recent payment activity once service is complete.
          </Typography.Paragraph>
          {session.error && <Alert className="stack-gap" type="warning" showIcon message={session.error} />}
          {workflowState.error && <Alert className="stack-gap" type="error" showIcon message={workflowState.error} />}
          {workflowState.sessionExpired && (
            <Alert
              className="stack-gap"
              type="warning"
              showIcon
              message="Session expired"
              description="Refresh your session or sign in again before retrying POS actions."
              action={
                <Space>
                  <Button size="small" onClick={() => void session.refresh()}>
                    Refresh Session
                  </Button>
                  <Button size="small" type="primary" href={loginUrl}>
                    Reauthenticate
                  </Button>
                </Space>
              }
            />
          )}

          <Routes>
            <Route
              path="/summary"
              element={
                <Space direction="vertical" size="middle" style={{ width: '100%' }}>
                  <Card title="POS Overview">
                    <Space direction="vertical" size="middle" style={{ width: '100%' }}>
                      <Space wrap>
                        <Input value={contextId} onChange={(event) => setContextId(event.target.value)} placeholder="Context Id" style={{ width: 260 }} />
                        <Input
                          value={transactionId}
                          onChange={(event) => setTransactionId(event.target.value)}
                          placeholder="Transaction Id"
                          style={{ width: 260 }}
                        />
                        <Button type="primary" icon={<SearchOutlined />} loading={loadingSummary} onClick={() => void loadSummary()}>
                          Load Summary
                        </Button>
                        <Button loading={loadingDetail} onClick={() => void loadDetail()}>
                          Load Transaction Detail
                        </Button>
                        <Button loading={loadingRecentPayments} onClick={() => void refreshRecentPayments()}>
                          Load Recent Payments
                        </Button>
                      </Space>
                      {summaryPayload ? (
                        <Descriptions bordered size="small" column={1}>
                          <Descriptions.Item label="Context Id">{summaryPayload.contextId}</Descriptions.Item>
                          <Descriptions.Item label="Summary">{summaryPayload.summary}</Descriptions.Item>
                          <Descriptions.Item label="Open Balance">
                            {summaryPayload.openBalance.toFixed(2)} {summaryPayload.currency}
                          </Descriptions.Item>
                          <Descriptions.Item label="Lifecycle Note">
                            Only restaurant orders that have completed service should appear here as payable checks for capture.
                          </Descriptions.Item>
                        </Descriptions>
                      ) : (
                        <Empty description="Load a POS summary to inspect which served orders are ready for payment capture." />
                      )}
                    </Space>
                  </Card>

                  <Card title="Transaction Detail">
                    {detailPayload?.transaction ? (
                      <Descriptions bordered size="small" column={1}>
                        <Descriptions.Item label="Context Id">{detailPayload.contextId}</Descriptions.Item>
                        <Descriptions.Item label="Summary">{detailPayload.summary}</Descriptions.Item>
                        <Descriptions.Item label="Transaction Id">{detailPayload.transaction.transactionId}</Descriptions.Item>
                        <Descriptions.Item label="Method">{detailPayload.transaction.paymentMethod}</Descriptions.Item>
                        <Descriptions.Item label="Amount">
                          {detailPayload.transaction.amount.toFixed(2)} {detailPayload.transaction.currency}
                        </Descriptions.Item>
                        <Descriptions.Item label="Status">
                          <Tag color={paymentStatusColor(detailPayload.transaction.status)}>{detailPayload.transaction.status}</Tag>
                        </Descriptions.Item>
                        <Descriptions.Item label="Next Step">{paymentProgressHint(detailPayload.transaction.status)}</Descriptions.Item>
                        <Descriptions.Item label="Captured At">{formatUtc(detailPayload.transaction.capturedAtUtc)}</Descriptions.Item>
                      </Descriptions>
                    ) : (
                      <Empty description="Load a transaction detail to inspect payable-check state and capture readiness." />
                    )}
                  </Card>

                  <Card title="Recent Payment Activity">
                    {recentPayload?.recentPayments.length ? (
                      <Table<PosPaymentActivity>
                        pagination={false}
                        rowKey={(record) => `${record.transactionId}-${record.capturedAtUtc}`}
                        dataSource={recentPayload.recentPayments}
                        columns={paymentColumns}
                      />
                    ) : (
                      <Empty description="Load recent payments to inspect the latest captured activity." />
                    )}
                  </Card>
                </Space>
              }
            />
            <Route
              path="/payments"
              element={
                <Space direction="vertical" size="middle" style={{ width: '100%' }}>
                  <Card title="Capture Payment">
                    <Space direction="vertical" size="middle" style={{ width: '100%' }}>
                      <Form<CapturePosPaymentRequest>
                        layout="vertical"
                        initialValues={{
                          contextId,
                          transactionId: 'POS-9001',
                          amount: 25.5,
                          currency: 'USD',
                          paymentMethod: 'card'
                        }}
                        onFinish={(values) => void submitCapturePayment(values)}
                      >
                        <Form.Item name="contextId" label="Context Id" rules={[{ required: true }]}>
                          <Input placeholder="Context Id" />
                        </Form.Item>
                        <Form.Item name="transactionId" label="Transaction Id" rules={[{ required: true }]}>
                          <Input placeholder="Transaction Id" />
                        </Form.Item>
                        <Form.Item name="amount" label="Amount" rules={[{ required: true, type: 'number', min: 0 }]}>
                          <InputNumber min={0} step={0.01} style={{ width: '100%' }} />
                        </Form.Item>
                        <Form.Item name="currency" label="Currency" rules={[{ required: true, min: 3, max: 3 }]}>
                          <Input placeholder="USD" />
                        </Form.Item>
                        <Form.Item name="paymentMethod" label="Payment Method" rules={[{ required: true }]}>
                          <Input placeholder="card" />
                        </Form.Item>
                        <Space>
                          <Button type="primary" htmlType="submit" loading={submittingPayment}>
                            Capture Payment Now
                          </Button>
                          <Button
                            disabled={!lastCaptureRequest}
                            onClick={() => lastCaptureRequest && void submitCapturePayment(lastCaptureRequest)}
                          >
                            Retry Last Capture
                          </Button>
                        </Space>
                      </Form>
                      <Typography.Text type="secondary">
                        Capture should be used only after kitchen and floor service complete the order, making the check payable.
                      </Typography.Text>
                    </Space>
                  </Card>

                  <Card title="Latest Capture Result">
                    {paymentResponse ? (
                      <Descriptions bordered size="small" column={1}>
                        <Descriptions.Item label="Context Id">{paymentResponse.contextId}</Descriptions.Item>
                        <Descriptions.Item label="Transaction Id">{paymentResponse.transactionId}</Descriptions.Item>
                        <Descriptions.Item label="Succeeded">{String(paymentResponse.succeeded)}</Descriptions.Item>
                        <Descriptions.Item label="Status">
                          <Tag color={paymentStatusColor(paymentResponse.status)}>{paymentResponse.status}</Tag>
                        </Descriptions.Item>
                        <Descriptions.Item label="Next Step">{paymentProgressHint(paymentResponse.status)}</Descriptions.Item>
                        <Descriptions.Item label="Captured At">{formatUtc(paymentResponse.capturedAtUtc)}</Descriptions.Item>
                        <Descriptions.Item label="Summary">{paymentResponse.summary}</Descriptions.Item>
                      </Descriptions>
                    ) : (
                      <Empty description="Run a capture to inspect the latest POS response." />
                    )}
                  </Card>

                  <Card title="Recent Capture Attempts">
                    <Table<PaymentAttempt>
                      pagination={false}
                      rowKey={(record) => `${record.response.transactionId}-${record.response.capturedAtUtc}`}
                      dataSource={paymentHistory}
                      locale={{ emptyText: 'No capture attempts recorded in this session.' }}
                      columns={[
                        { title: 'Transaction Id', render: (_, record) => record.response.transactionId },
                        { title: 'Method', render: (_, record) => record.request.paymentMethod },
                        {
                          title: 'Amount',
                          render: (_, record) => `${record.request.amount.toFixed(2)} ${record.request.currency}`
                        },
                        {
                          title: 'Status',
                          render: (_, record) => (
                            <Tag color={paymentStatusColor(record.response.status)}>{record.response.status}</Tag>
                          )
                        },
                        { title: 'Summary', render: (_, record) => record.response.summary },
                        { title: 'Lifecycle Step', render: (_, record) => paymentProgressHint(record.response.status) }
                      ]}
                    />
                  </Card>
                </Space>
              }
            />
            <Route
              path="/session"
              element={
                <Card title="Session Details">
                  <pre>{JSON.stringify(session.profile, null, 2)}</pre>
                </Card>
              }
            />
            <Route path="/" element={<Navigate to="/summary" replace />} />
            <Route path="*" element={<Navigate to="/summary" replace />} />
          </Routes>
        </Layout.Content>
      </Layout>
    </Layout>
  );
}

function providerLabel(provider: IdentityProvider) {
  switch (provider) {
    case 1:
      return 'manual';
    case 2:
      return 'google';
    default:
      return 'unknown';
  }
}

function paymentStatusColor(status: string) {
  switch (status.toLowerCase()) {
    case 'captured':
    case 'paid':
      return 'green';
    case 'payable':
    case 'ready':
      return 'blue';
    case 'pending':
    case 'authorized':
      return 'orange';
    case 'failed':
    case 'blocked':
      return 'red';
    default:
      return 'default';
  }
}

function paymentProgressHint(status: string) {
  switch (status.toLowerCase()) {
    case 'payable':
    case 'ready':
      return 'ready for payment capture after service completion';
    case 'pending':
    case 'authorized':
      return 'payment is in progress and should be monitored before retrying';
    case 'captured':
    case 'paid':
      return 'payment is complete and the restaurant workflow can close';
    case 'failed':
    case 'blocked':
      return 'operator review is required before attempting another capture';
    default:
      return 'payment state is being resolved against the restaurant lifecycle';
  }
}

function formatUtc(value: string) {
  return new Date(value).toLocaleString('en-US', {
    dateStyle: 'medium',
    timeStyle: 'short',
    timeZone: 'UTC'
  });
}

export default App;
