import { ArrowSquareOut } from "@phosphor-icons/react/dist/ssr/ArrowSquareOut";
import { ClockCountdown } from "@phosphor-icons/react/dist/ssr/ClockCountdown";
import { Button } from "@pythnetwork/component-library/Button";
import { Card } from "@pythnetwork/component-library/Card";
import { StatCard } from "@pythnetwork/component-library/StatCard";
import { lookup as lookupPublisher } from "@pythnetwork/known-publishers";

import styles from "./index.module.scss";
import { PublishersCard } from "./publishers-card";
import { getPublishers } from "../../services/clickhouse";
import { getPublisherCaps } from "../../services/hermes";
import {
  getDelState,
  getClaimableRewards,
  getDistributedRewards,
} from "../../services/staking";
import { ExplainAverage } from "../Explanations";
import { FormattedDate } from "../FormattedDate";
import { FormattedTokens } from "../FormattedTokens";
import { PublisherIcon } from "../PublisherIcon";
import { SemicircleMeter, Label } from "../SemicircleMeter";
import { TokenIcon } from "../TokenIcon";

const INITIAL_REWARD_POOL_SIZE = 60_000_000_000_000n;

export const Publishers = async () => {
  const [publishers, oisStats] = await Promise.all([
    getPublishers(),
    getOisStats(),
  ]);

  const rankingTime = publishers[0]?.timestamp;
  const scoreTime = publishers[0]?.scoreTime;

  return (
    <div className={styles.publishers}>
      <div className={styles.headerContainer}>
        <h1 className={styles.header}>Publishers</h1>
        {rankingTime && (
          <div className={styles.rankingsLastUpdated}>
            <span>
              Rankings last updated{" "}
              <FormattedDate
                value={rankingTime}
                dateStyle="long"
                timeStyle="long"
                timeZone="utc"
              />
            </span>
            <ClockCountdown className={styles.clockIcon} />
          </div>
        )}
      </div>
      <div className={styles.body}>
        <section className={styles.stats}>
          <StatCard
            variant="primary"
            header="Active Publishers"
            stat={publishers.length}
          />
          <StatCard
            header="Average Feed Score"
            corner={<ExplainAverage scoreTime={scoreTime} />}
            stat={(
              publishers.reduce(
                (sum, publisher) => sum + publisher.averageScore,
                0,
              ) / publishers.length
            ).toFixed(2)}
          />
          <Card
            title="Oracle Integrity Staking (OIS)"
            className={styles.oisCard}
            toolbar={
              <Button
                href="https://staking.pyth.network"
                target="_blank"
                size="sm"
                variant="outline"
                afterIcon={ArrowSquareOut}
              >
                Staking App
              </Button>
            }
          >
            <SemicircleMeter
              width={340}
              height={340}
              value={Number(oisStats.totalStaked)}
              maxValue={oisStats.maxPoolSize ?? 0}
              className={styles.oisPool ?? ""}
            >
              <Label className={styles.title}>PYTH Staking Pool</Label>
              <p className={styles.poolUsed}>
                <FormattedTokens
                  mode="wholePart"
                  tokens={oisStats.totalStaked}
                />
              </p>
              <p className={styles.poolTotal}>
                /{" "}
                <FormattedTokens
                  mode="wholePart"
                  tokens={BigInt(oisStats.maxPoolSize ?? 0)}
                />
              </p>
            </SemicircleMeter>
            <div className={styles.oisStats}>
              <StatCard
                header="Total Staked"
                variant="tertiary"
                stat={
                  <>
                    <TokenIcon />
                    <FormattedTokens tokens={oisStats.totalStaked} />
                  </>
                }
              />
              <StatCard
                header="Total Rewards Distributed"
                variant="tertiary"
                stat={
                  <>
                    <TokenIcon />
                    <FormattedTokens tokens={oisStats.rewardsDistributed} />
                  </>
                }
              />
            </div>
          </Card>
        </section>
        <PublishersCard
          className={styles.publishersCard}
          explainAverage={<ExplainAverage scoreTime={scoreTime} />}
          publishers={publishers.map(
            ({ key, rank, inactiveFeeds, activeFeeds, averageScore }) => {
              const knownPublisher = lookupPublisher(key);
              return {
                id: key,
                ranking: rank,
                activeFeeds: activeFeeds,
                inactiveFeeds: inactiveFeeds,
                averageScore,
                ...(knownPublisher && {
                  name: knownPublisher.name,
                  icon: <PublisherIcon knownPublisher={knownPublisher} />,
                }),
              };
            },
          )}
        />
      </div>
    </div>
  );
};

const getOisStats = async () => {
  const [delState, claimableRewards, distributedRewards, publisherCaps] =
    await Promise.all([
      getDelState(),
      getClaimableRewards(),
      getDistributedRewards(),
      getPublisherCaps(),
    ]);

  return {
    totalStaked:
      sumDelegations(delState.delState) + sumDelegations(delState.selfDelState),
    rewardsDistributed:
      claimableRewards + INITIAL_REWARD_POOL_SIZE - distributedRewards,
    maxPoolSize: publisherCaps.parsed?.[0]?.publisher_stake_caps
      .map(({ cap }) => cap)
      .reduce((acc, value) => acc + value),
  };
};

const sumDelegations = (
  values: { totalDelegation: bigint; deltaDelegation: bigint }[],
) =>
  values.reduce(
    (acc, value) => acc + value.totalDelegation + value.deltaDelegation,
    0n,
  );
