import { Box, Tabs, Button, Center, Loader, Divider } from '@tidbcloud/uikit'
import { capitalize } from 'lodash-es'
import { observer } from 'mobx-react'
import React, { useState, useEffect, useMemo } from 'react'
import { Route, Switch, matchPath, Redirect, useLocation, useHistory, Link } from 'react-router-dom'

import { PageAccessGuard } from 'dbaas/contexts/access-control'
import { PageShell } from 'dbaas/layouts/v5/page'
import { OrgPlanStatus } from 'dbaas/screens/Plans/constant'
import { useGetMspCustomer, useGetPartnerByCustomerId } from 'dbaas/services/account'
import { CentralUserProfileOrgOrgTag } from 'dbaas/services/account/interface'
import { useListStripeInvoices, useListBillingConfigs, useGetIsEnabledBills } from 'dbaas/services/billing'
import useStores from 'dbaas/stores/useStores'

import { BillingProfile } from './BillingProfile'
import { Bills } from './Bills'
import { BudgetAlert } from './BudgetAlert'
import { useCurrentBillingCycle } from './components/BillingOverview'
import { Contracts } from './Contract'
import { CostExplorer } from './CostExplorer'
import { Credits } from './Credits'
import { Discounts } from './Discounts'
import { Invoices } from './Invoices'
import { ResellerPayment, MSPPayment, ResalePayment } from './Marketplace'
import { Payments } from './Payments'

const HistoryShell: React.FC<React.PropsWithChildren<{}>> = ({ children }) => {
  const history = useHistory()
  return (
    <PageShell
      headerProps={{
        withBack: true,
        onBackClick: () => {
          history.push('/org-settings/billing')
        }
      }}
      bodyProps={{
        px: 0,
        py: 0
      }}
      title="History"
    >
      {children}
    </PageShell>
  )
}

const Billing = observer(() => {
  const {
    actions,
    store: { tenantData, config }
  } = useStores()
  const isOnDemand = tenantData.plan === OrgPlanStatus.ON_DEMAND
  const isClosing = tenantData.plan === OrgPlanStatus.CLOSING
  const isPoC = tenantData.plan === OrgPlanStatus.POC
  const basePath = '/org-settings/billing'
  const location = useLocation()
  const history = useHistory()
  const { enabledCostExplorer } = config

  const [activeTab, setActiveTab] = useState<string>('')

  const { data: billingConfigs } = useListBillingConfigs(tenantData.id)

  const isMarketResellerCustomer =
    !!tenantData.org_tag &&
    Array.of<string>(
      CentralUserProfileOrgOrgTag.aws_cppo_customer,
      CentralUserProfileOrgOrgTag.gcp_mcpo_customer
    ).includes(tenantData.org_tag)

  const isMSPCustomer = tenantData.org_tag === CentralUserProfileOrgOrgTag.msp_customer
  const isResaleCustomer = tenantData.org_tag === CentralUserProfileOrgOrgTag.resale_customer

  const isPartnerCustomer = isMarketResellerCustomer || isMSPCustomer || isResaleCustomer

  const { data: mspCustomer } = useGetMspCustomer(tenantData.id, {
    query: { enabled: isMSPCustomer }
  })

  const { data: resellerCustomer } = useGetPartnerByCustomerId(tenantData.id, {
    query: {
      enabled: isMarketResellerCustomer || isResaleCustomer
    }
  })

  const isInHistory = location.pathname.includes('history')

  const historyBillingConfig = useMemo(() => {
    return (billingConfigs || []).find((cfg) => cfg.status === 'Closing' || cfg.status === 'Closed')!
  }, [billingConfigs])

  const activeBillingConfig = useMemo(() => {
    return (billingConfigs || []).find((cfg) => cfg.status === 'Active')!
  }, [billingConfigs])

  const enableHistory = isPartnerCustomer && !!historyBillingConfig

  const { data: invoices } = useListStripeInvoices(tenantData.id, activeBillingConfig?.billing_config_id, {
    query: {
      enabled: !!(tenantData.id && activeBillingConfig?.billing_config_id && activeBillingConfig),
      refetchInterval: false
    }
  })

  const { data: billsConfig } = useGetIsEnabledBills(tenantData.id, activeBillingConfig?.billing_config_id, {
    query: {
      enabled: !!(tenantData.id && activeBillingConfig?.billing_config_id && activeBillingConfig && isPartnerCustomer),
      refetchInterval: false
    }
  })

  const customerWithListPrice = billsConfig?.bills_enabled

  const currentMonthBill = useCurrentBillingCycle(tenantData.id, activeBillingConfig)

  // if users already have invoices before link account
  // should show invoices
  const hideInvoices = config.hideInvoices && invoices && !invoices.length

  const tabsMap: Record<string, { component: React.ReactNode; title?: string; hidden?: boolean }> = useMemo(() => {
    const selectedBillingConfig = isInHistory ? historyBillingConfig : activeBillingConfig
    const tabs = {
      invoices: {
        component: (
          <Invoices
            hasDraftInvoice={!currentMonthBill.data?.invoice_generated}
            orgId={tenantData?.id}
            billingConfig={selectedBillingConfig}
          />
        ),
        hidden: hideInvoices
      },
      payments: {
        component: (
          <Payments disabled={isPartnerCustomer} billingConfig={selectedBillingConfig} orgTag={tenantData.org_tag} />
        ),
        title: 'Payment Methods',
        hidden: config.hidePaymentMethod
      },
      bills: {
        component: (
          <>
            {isMSPCustomer && customerWithListPrice && !isInHistory && (
              <MSPPayment data={mspCustomer} billsEnabled mb="xl" />
            )}
            {isResaleCustomer && customerWithListPrice && !isInHistory && (
              <ResalePayment data={resellerCustomer} billsEnabled mb="xl" />
            )}
            {isMarketResellerCustomer && !isInHistory && (
              <ResellerPayment
                payable
                withBills
                partnerName={resellerCustomer?.name || ''}
                mb="xl"
                orgTag={tenantData.org_tag!}
              />
            )}
            <Bills billingConfig={selectedBillingConfig} />
          </>
        )
      },
      credits: {
        component: <Credits billingConfig={selectedBillingConfig} />
      },
      contract: {
        component: <Contracts billingConfig={selectedBillingConfig} disabled={isMSPCustomer || isResaleCustomer} />
      },
      discounts: {
        component: <Discounts billingConfig={selectedBillingConfig} />
      },
      'billing-profile': {
        title: 'Billing Profile',
        component: <BillingProfile disabled={isMSPCustomer || isResaleCustomer} />
      },
      'cost-explorer': {
        title: 'Cost Explorer',
        component: (
          <>
            {isMSPCustomer && customerWithListPrice && !isInHistory && (
              <>
                <MSPPayment data={mspCustomer} billsEnabled /> <Divider mx="-xl" my="xl" />
              </>
            )}
            {isResaleCustomer && customerWithListPrice && !isInHistory && (
              <>
                <ResalePayment data={resellerCustomer} billsEnabled /> <Divider mx="-xl" my="xl" />
              </>
            )}
            <CostExplorer billingConfig={selectedBillingConfig} />
          </>
        ),
        hidden: !enabledCostExplorer
      },
      'budget-alert': {
        title: 'Budgets',
        component: <BudgetAlert />
      }
    }
    return tabs
  }, [
    hideInvoices,
    config.hidePaymentMethod,
    currentMonthBill,
    tenantData.id,
    tenantData.org_tag,
    isMSPCustomer,
    isResaleCustomer,
    activeBillingConfig,
    enabledCostExplorer,
    resellerCustomer,
    isMarketResellerCustomer,
    isInHistory,
    mspCustomer,
    customerWithListPrice,
    historyBillingConfig,
    isPartnerCustomer
  ])

  useEffect(() => {
    async function fetcher() {
      // tricky to update remaining credits and current usage synchronously
      // actions.fetchTenant()
      actions.refreshOrgData()
    }

    fetcher()
  }, [actions])

  const tabs = useMemo(() => {
    return (
      isOnDemand || isClosing
        ? [
            'bills',
            'cost-explorer',
            'budget-alert',
            'invoices',
            'payments',
            'billing-profile',
            'credits',
            'discounts',
            'contract'
          ]
        : isPoC
          ? [
              'bills',
              'cost-explorer',
              'budget-alert',
              'payments',
              'billing-profile',
              'credits',
              'discounts',
              'contract'
            ]
          : ['payments', 'billing-profile', 'credits', 'discounts', 'contract']
    )
      .filter((item) => !!item && !!tabsMap[item])
      .map((item) => {
        const tab = tabsMap[item]
        return {
          // path: `${basePath}${isMSPCustomer ? '/history/' : '/'}${item}`,
          path: `${basePath}/${item}`,
          component: tab.component,
          title: tab.title ?? capitalize(item),
          hidden: tab.hidden
        }
      })
  }, [isOnDemand, isPoC, tabsMap, isClosing])

  const currentTabs = tabs.filter((t) => {
    if (isMarketResellerCustomer && customerWithListPrice) {
      return /bills|cost-explorer|budget-alert/.test(t.path)
    }
    // cppo only shows bills, cost explorer, payments
    if (isMarketResellerCustomer) {
      return (customerWithListPrice ? /bills|cost-explorer|payments/ : /payments/).test(t.path)
    }
    return true
  })

  const historyTabs = tabs.map((t) => ({
    ...t,
    path: `${basePath}/history${t.path.replace(basePath, '')}`
  }))

  useEffect(() => {
    const tab = (isInHistory ? historyTabs : currentTabs).find((tab) => {
      return !!matchPath(location.pathname, {
        path: tab.path,
        exact: true
      })
    })

    setActiveTab(tab ? tab.path : '')
  }, [currentTabs, location.pathname, isInHistory])

  const TabsElems = (withHistory: boolean) => {
    const redirectPath = withHistory ? `${basePath}/history` : basePath
    const realTabs = withHistory ? historyTabs : currentTabs
    return (
      <>
        <Tabs
          value={activeTab}
          styles={() => ({
            root: {
              padding: '0 24px'
            },
            list: {
              '::before': {
                border: 'none'
              }
            },
            tabLabel: {
              fontSize: 14
            }
          })}
        >
          <Tabs.List>
            {realTabs.map((item) => {
              if (item.hidden) {
                return null
              }
              return (
                <Tabs.Tab key={item.path} value={item.path} onClick={() => history.push(item.path)}>
                  {item.title}
                </Tabs.Tab>
              )
            })}
          </Tabs.List>
        </Tabs>
        <Switch>
          {realTabs.map((item) => {
            if (item.hidden) {
              return null
            }
            return (
              <Route key={item.path} path={item.path}>
                <Box
                  p={24}
                  h="calc(100vh - 100px)"
                  sx={() => ({
                    overflow: 'auto'
                  })}
                >
                  {item.component}
                </Box>
              </Route>
            )
          })}
          <Redirect
            exact
            path={`${redirectPath}`}
            to={`${redirectPath}/${
              tenantData.plan === OrgPlanStatus.FREE_TRIAL ||
              tenantData.plan === OrgPlanStatus.NEW_USER ||
              (isMarketResellerCustomer && !customerWithListPrice && !withHistory)
                ? 'payments'
                : 'bills'
            }`}
          />
        </Switch>
      </>
    )
  }

  if (!billingConfigs || (isInHistory && !historyBillingConfig)) {
    return (
      <Center mt={48}>
        <Loader />
      </Center>
    )
  }

  const HistoryButton = enableHistory ? (
    <Button
      component={Link}
      to={`${basePath}/history`}
      variant="default"
      size="sm"
      sx={(theme) => ({
        ':hover': {
          textDecoration: 'none',
          color: theme.colors.carbon[8]
        }
      })}
    >
      History
    </Button>
  ) : null

  const HistoryRoute = (
    <Switch>
      <Route path={`${basePath}/history`}>
        <HistoryShell>{TabsElems(true)}</HistoryShell>
      </Route>
      {(isMSPCustomer || isResaleCustomer) && !customerWithListPrice && (
        <Route path={basePath}>
          <PageShell
            title="Billing"
            headerProps={{
              rightSection: HistoryButton
            }}
            bodyProps={{
              py: 0,
              px: 24
            }}
          >
            {isMSPCustomer && <MSPPayment data={mspCustomer} hasBills={!!historyBillingConfig} />}
            {isResaleCustomer && <ResalePayment data={resellerCustomer} hasBills={!!historyBillingConfig} />}
          </PageShell>
        </Route>
      )}
    </Switch>
  )

  return (
    <Box h="100%">
      {(isMSPCustomer || isResaleCustomer) && !customerWithListPrice ? (
        HistoryRoute
      ) : (
        <>
          {HistoryRoute}
          {!isInHistory && (
            <PageShell
              title="Billing"
              headerProps={{
                rightSection: HistoryButton
              }}
              bodyProps={{
                py: 0,
                px: 0
              }}
            >
              {TabsElems(false)}
            </PageShell>
          )}
        </>
      )}
    </Box>
  )
})

export const BillingGuard = () => {
  return (
    <PageAccessGuard
      id="OrgBillingGate"
      fallback={(defaultFallback) => <PageShell title="Billing">{defaultFallback}</PageShell>}
    >
      <Billing />
    </PageAccessGuard>
  )
}

export default BillingGuard
