import { StatusBar } from 'expo-status-bar'
import { useEffect, useMemo, useState } from 'react'
import { ActivityIndicator, RefreshControl } from 'react-native'
import * as Tamagui from 'tamagui'

import { config } from './tamagui.config'
import {
  API_BASE_URL,
  ApiUser,
  DashboardData,
  WalletData,
  clearStoredToken,
  endpoints,
  getStoredToken,
  login,
  storeToken,
  unwrapCollection,
} from './src/api/client'

const {
  Button,
  Card,
  H1,
  H2,
  Input,
  Paragraph,
  ScrollView,
  Separator,
  SizableText,
  Spinner,
  TamaguiProvider,
  Text,
  Theme,
  XStack,
  YStack,
} = Tamagui as any

type TabKey = 'home' | 'orders' | 'logs' | 'numbers' | 'boost' | 'tools'

const tabs: { key: TabKey; label: string }[] = [
  { key: 'home', label: 'Home' },
  { key: 'orders', label: 'Orders' },
  { key: 'logs', label: 'Logs' },
  { key: 'numbers', label: 'Numbers' },
  { key: 'boost', label: 'Boost' },
  { key: 'tools', label: 'Tools' },
]

const catalogLoaders: Record<Exclude<TabKey, 'home'>, () => Promise<unknown>> = {
  orders: endpoints.orders,
  logs: endpoints.logs,
  numbers: endpoints.numbersServices,
  boost: endpoints.boostServices,
  tools: endpoints.tools,
}

export default function App() {
  return (
    <TamaguiProvider config={config} defaultTheme="light">
      <Theme name="light">
        <AppShell />
        <StatusBar style="dark" />
      </Theme>
    </TamaguiProvider>
  )
}

function AppShell() {
  const [booting, setBooting] = useState(true)
  const [token, setToken] = useState<string | null>(null)
  const [user, setUser] = useState<ApiUser | null>(null)

  useEffect(() => {
    let active = true

    async function restoreSession() {
      try {
        const storedToken = await getStoredToken()
        if (!storedToken) return

        const profile = await endpoints.me()
        if (!active) return

        setToken(storedToken)
        setUser(profile.user)
      } catch {
        await clearStoredToken()
      } finally {
        if (active) setBooting(false)
      }
    }

    restoreSession()

    return () => {
      active = false
    }
  }, [])

  async function handleAuthenticated(nextToken: string, nextUser: ApiUser) {
    await storeToken(nextToken)
    setToken(nextToken)
    setUser(nextUser)
  }

  async function handleLogout() {
    try {
      await endpoints.logout()
    } catch {
      // Local logout should still happen if the token is already invalid server-side.
    }
    await clearStoredToken()
    setToken(null)
    setUser(null)
  }

  if (booting) {
    return (
      <YStack f={1} ai="center" jc="center" bg="$background" gap="$3">
        <Spinner size="large" color="$blue10" />
        <Text color="$color10">Opening Socanum</Text>
      </YStack>
    )
  }

  if (!token || !user) {
    return <LoginScreen onAuthenticated={handleAuthenticated} />
  }

  return <DashboardScreen user={user} onLogout={handleLogout} />
}

function LoginScreen({
  onAuthenticated,
}: {
  onAuthenticated: (token: string, user: ApiUser) => Promise<void>
}) {
  const [email, setEmail] = useState('')
  const [password, setPassword] = useState('')
  const [loading, setLoading] = useState(false)
  const [error, setError] = useState<string | null>(null)

  async function submit() {
    setLoading(true)
    setError(null)

    try {
      const result = await login(email.trim(), password)
      await onAuthenticated(result.access_token, result.user)
    } catch (err) {
      setError(err instanceof Error ? err.message : 'Unable to sign in.')
    } finally {
      setLoading(false)
    }
  }

  return (
    <YStack f={1} bg="$background" px="$4" py="$8" jc="center" gap="$5">
      <YStack gap="$2">
        <H1 size="$10">Socanum</H1>
        <Paragraph color="$color10">
          Sign in with your buyer account to manage orders, wallet, numbers, logs, boosts, and tools.
        </Paragraph>
      </YStack>

      <Card bordered bg="$backgroundStrong" p="$4" gap="$3" br="$4">
        <Input
          autoCapitalize="none"
          keyboardType="email-address"
          placeholder="Email address"
          value={email}
          onChangeText={setEmail}
        />
        <Input
          placeholder="Password"
          secureTextEntry
          value={password}
          onChangeText={setPassword}
        />
        {error ? <Text color="$red10">{error}</Text> : null}
        <Button theme="blue" disabled={loading || !email || !password} onPress={submit}>
          {loading ? <ActivityIndicator color="#fff" /> : 'Sign in'}
        </Button>
      </Card>

      <Text color="$color9" fontSize="$2">
        API: {API_BASE_URL}
      </Text>
    </YStack>
  )
}

function DashboardScreen({ user, onLogout }: { user: ApiUser; onLogout: () => Promise<void> }) {
  const [activeTab, setActiveTab] = useState<TabKey>('home')
  const [dashboard, setDashboard] = useState<DashboardData | null>(null)
  const [wallet, setWallet] = useState<WalletData | null>(null)
  const [items, setItems] = useState<unknown[]>([])
  const [loading, setLoading] = useState(false)
  const [refreshing, setRefreshing] = useState(false)
  const [error, setError] = useState<string | null>(null)

  const displayUser = dashboard?.user || user
  const balance = wallet?.balance || displayUser.balance || '0.00'
  const currency = wallet?.currency || displayUser.currency || 'NGN'

  async function load(tab = activeTab) {
    setLoading(true)
    setError(null)

    try {
      if (tab === 'home') {
        const [nextDashboard, nextWallet] = await Promise.all([
          endpoints.dashboard(),
          endpoints.wallet(),
        ])
        setDashboard(nextDashboard)
        setWallet(nextWallet)
        return
      }

      const result = await catalogLoaders[tab]()
      setItems(unwrapCollection(result as never))
    } catch (err) {
      setError(err instanceof Error ? err.message : 'Unable to load data.')
    } finally {
      setLoading(false)
      setRefreshing(false)
    }
  }

  useEffect(() => {
    load(activeTab)
  }, [activeTab])

  const statCards = useMemo(() => {
    const stats = dashboard?.stats || {}
    return [
      ['Logs', stats.purchased_logs ?? 0],
      ['Tools', stats.purchased_tools ?? 0],
      ['Boosts', stats.purchased_boosts ?? 0],
      ['Numbers', stats.purchased_numbers ?? 0],
      ['Deposits', `${currency} ${stats.total_deposits ?? '0.00'}`],
      ['Spend', `${currency} ${stats.total_spend ?? '0.00'}`],
    ]
  }, [currency, dashboard])

  async function refresh() {
    setRefreshing(true)
    await load(activeTab)
  }

  return (
    <YStack f={1} bg="$background">
      <ScrollView
        f={1}
        refreshControl={<RefreshControl refreshing={refreshing} onRefresh={refresh} />}
        contentContainerStyle={{ padding: 16, paddingTop: 56, gap: 16 }}
      >
        <XStack ai="center" jc="space-between" gap="$3">
          <YStack f={1}>
            <SizableText color="$color10">Welcome back</SizableText>
            <H2 numberOfLines={1}>{displayUser.name || displayUser.username || 'Buyer'}</H2>
          </YStack>
          <Button size="$3" chromeless onPress={onLogout}>
            Logout
          </Button>
        </XStack>

        <Card bordered bg="$blue3" p="$4" gap="$2" br="$4">
          <Text color="$blue11">Wallet Balance</Text>
          <H1 color="$blue12">
            {currency} {balance}
          </H1>
        </Card>

        <ScrollView horizontal showsHorizontalScrollIndicator={false}>
          <XStack gap="$2" py="$1">
            {tabs.map((tab) => (
              <Button
                key={tab.key}
                size="$3"
                theme={activeTab === tab.key ? 'blue' : undefined}
                onPress={() => setActiveTab(tab.key)}
              >
                {tab.label}
              </Button>
            ))}
          </XStack>
        </ScrollView>

        {error ? (
          <Card bordered bg="$red3" p="$3" br="$4">
            <Text color="$red11">{error}</Text>
          </Card>
        ) : null}

        {loading && !refreshing ? <Spinner color="$blue10" /> : null}

        {activeTab === 'home' ? (
          <YStack gap="$3">
            <XStack fw="wrap" gap="$3">
              {statCards.map(([label, value]) => (
                <Card key={label} bordered p="$3" br="$4" width="47%" gap="$1">
                  <Text color="$color10" fontSize="$2">
                    {label}
                  </Text>
                  <SizableText size="$6" fontWeight="700">
                    {value}
                  </SizableText>
                </Card>
              ))}
            </XStack>
            <RecentActivity title="Recent Orders" rows={dashboard?.recent_orders || []} />
            <RecentActivity title="Recent Numbers" rows={dashboard?.recent_numbers || []} />
          </YStack>
        ) : (
          <CatalogList title={tabs.find((tab) => tab.key === activeTab)?.label || 'Items'} rows={items} />
        )}
      </ScrollView>
    </YStack>
  )
}

function RecentActivity({ title, rows }: { title: string; rows: unknown[] }) {
  return (
    <Card bordered p="$4" br="$4" gap="$3">
      <H2 size="$5">{title}</H2>
      <Separator />
      {rows.length === 0 ? (
        <Text color="$color10">No recent activity yet.</Text>
      ) : (
        rows.slice(0, 5).map((row, index) => <RowPreview key={index} row={row} />)
      )}
    </Card>
  )
}

function CatalogList({ title, rows }: { title: string; rows: unknown[] }) {
  return (
    <Card bordered p="$4" br="$4" gap="$3">
      <H2 size="$5">{title}</H2>
      <Separator />
      {rows.length === 0 ? (
        <Text color="$color10">No records returned.</Text>
      ) : (
        rows.slice(0, 20).map((row, index) => <RowPreview key={index} row={row} />)
      )}
    </Card>
  )
}

function RowPreview({ row }: { row: unknown }) {
  const record = row && typeof row === 'object' ? (row as Record<string, unknown>) : { value: row }
  const title =
    String(record.name || record.title || record.service_name || record.category_name || record.order_id || record.id || 'Record')
  const subtitle = Object.entries(record)
    .filter(([, value]) => typeof value === 'string' || typeof value === 'number')
    .slice(0, 3)
    .map(([key, value]) => `${key}: ${value}`)
    .join('  ')

  return (
    <YStack gap="$1" py="$2">
      <SizableText fontWeight="700">{title}</SizableText>
      {subtitle ? (
        <Text color="$color10" fontSize="$2" numberOfLines={2}>
          {subtitle}
        </Text>
      ) : null}
    </YStack>
  )
}
