import { useEffect, useState } from 'react';
import { Link, useNavigate, useOutletContext } from 'react-router-dom';
import { RequestError } from 'octokit';

import { useOctokit } from 'context/OctokitContext';
import { GitCommitWithBranch, OutletContextType } from '../../../../types';
import { useGQLClient } from 'context/GQLClientContext';
import { Button, Heading, Avatar, Tag } from 'components/shared';
import { getInitials } from 'utils/geInitials';
import {
  BranchStrokeIcon,
  CheckRoundFilledIcon,
  ClockIcon,
  CursorBoxIcon,
  GithubStrokeIcon,
  GlobeIcon,
  LinkIcon,
  CalendarDaysIcon,
} from 'components/shared/CustomIcon';
import { Activity } from 'components/projects/project/overview/Activity';
import { OverviewInfo } from 'components/projects/project/overview/OverviewInfo';
import { relativeTimeMs } from 'utils/time';
import { Domain, DomainStatus } from 'gql-client';
import { AuctionCard } from 'components/projects/project/overview/Activity/AuctionCard';

const COMMITS_PER_PAGE = 4;

const OverviewTabPanel = () => {
  const { octokit } = useOctokit();
  const navigate = useNavigate();
  const [activities, setActivities] = useState<GitCommitWithBranch[]>([]);
  const [fetchingActivities, setFetchingActivities] = useState(true);
  const [liveDomain, setLiveDomain] = useState<Domain>();

  const client = useGQLClient();

  const { project } = useOutletContext<OutletContextType>();

  useEffect(() => {
    setFetchingActivities(true);
    // TODO: Save repo commits in DB and avoid using GitHub API in frontend
    // TODO: Figure out fetching latest commits for all branches
    const fetchRepoActivity = async () => {
      try {
        const [owner, repo] = project.repository.split('/');

        if (!repo) {
          // Do not fetch branches if repo not available
          return;
        }

        // Get all branches in project repo
        const result = await octokit.rest.repos.listBranches({
          owner,
          repo,
        });

        // Get first 4 commits from repo branches
        const commitsByBranchPromises = result.data.map(async (branch) => {
          const result = await octokit.rest.repos.listCommits({
            owner,
            repo,
            sha: branch.commit.sha,
            per_page: COMMITS_PER_PAGE,
          });

          return result.data.map((data) => ({
            ...data,
            branch,
          }));
        });

        const commitsByBranch = await Promise.all(commitsByBranchPromises);
        const commitsWithBranch = commitsByBranch.flat();

        // Order commits by date and set latest 4 commits in activity section
        const orderedCommits = commitsWithBranch
          .sort(
            (a, b) =>
              new Date(b.commit.author!.date!).getTime() -
              new Date(a.commit.author!.date!).getTime(),
          )
          .slice(0, COMMITS_PER_PAGE);

        setActivities(orderedCommits);
      } catch (err) {
        if (!(err instanceof RequestError)) {
          throw err;
        }

        // TODO: Show warning in activity section on request error
        console.log(err.message);
      } finally {
        setFetchingActivities(false);
      }
    };

    fetchRepoActivity();
  }, [octokit, project]);

  useEffect(() => {
    const fetchLiveProdDomain = async () => {
      const { domains } = await client.getDomains(project.id, {
        branch: project.prodBranch,
        status: DomainStatus.Live,
      });

      if (domains.length === 0) {
        return;
      }

      setLiveDomain(domains[0]);
    };

    fetchLiveProdDomain();
  }, [project]);

  return (
    <div className="grid grid-cols-5 gap-6 md:gap-[72px]">
      <div className="col-span-5 md:col-span-3">
        <div className="flex items-center gap-4 mb-6">
          <Avatar
            size={48}
            initials={getInitials(project.name)}
            imageSrc={project.icon}
            type="blue"
          />
          <div className="flex-1 space-y-1 overflow-hidden">
            <Heading className="text-lg leading-6 font-medium truncate dark:text-foreground">
              {project.name}
            </Heading>
            {project.deployments &&
              project.deployments.length > 0 &&
              project.deployments.map((deployment, index) => (
                <p>
                  <a
                    key={index}
                    href={`https://${project.name.toLowerCase()}.${deployment.deployer.baseDomain}`}
                    className="text-sm text-elements-low-em dark:text-foreground tracking-tight truncate"
                  >
                    {deployment.deployer.baseDomain}
                  </a>
                </p>
              ))}
          </div>
        </div>
        <OverviewInfo label="Domain" icon={<GlobeIcon />}>
          {liveDomain ? (
            <Tag type="positive" size="xs" leftIcon={<CheckRoundFilledIcon />}>
              Connected
            </Tag>
          ) : (
            <div className="flex items-center gap-2">
              <Tag type="attention" size="xs" leftIcon={<ClockIcon />}>
                Not connected
              </Tag>
              <Button
                onClick={() => {
                  navigate('settings/domains');
                }}
                variant="tertiary"
                size="sm"
              >
                SETUP
              </Button>
            </div>
          )}
        </OverviewInfo>
        {project.deployments.length !== 0 ? (
          <>
            {/* SOURCE */}
            <OverviewInfo label="Source" icon={<GithubStrokeIcon />}>
              <div className="flex gap-2 items-center">
                <BranchStrokeIcon className="text-elements-low-em dark:text-foreground w-4 h-5" />
                <span className="text-elements-high-em dark:text-foreground-secondary text-sm tracking-tighter">
                  {project.deployments[0]?.branch}
                </span>
              </div>
            </OverviewInfo>

            {/* DEPLOYMENT */}
            <OverviewInfo label="Deployment URL" icon={<CursorBoxIcon />}>
              {project.deployments &&
                project.deployments.length > 0 &&
                project.deployments.map((deployment) => (
                  <div className="flex gap-2 items-center">
                    <Link
                      to={`https://${project.name.toLowerCase()}.${deployment.deployer.baseDomain}`}
                    >
                      <span className="text-controls-primary dark:text-foreground group hover:border-controls-primary transition-colors border-b border-b-transparent flex gap-2 items-center text-sm tracking-tight">
                        {`https://${project.name.toLowerCase()}.${deployment.deployer.baseDomain}`}
                        <LinkIcon className="group-hover:rotate-45 transition-transform" />
                      </span>
                    </Link>
                  </div>
                ))}
            </OverviewInfo>

            {/* DEPLOYMENT DATE */}
            <OverviewInfo label="Deployment date" icon={<CalendarDaysIcon />}>
              <div className="flex gap-2 items-center text-elements-high-em dark:text-foreground text-sm tracking-tighter">
                <span>{relativeTimeMs(project.deployments[0].createdAt)}</span>
                by
                <Avatar
                  // TODO: add imageSrc
                  // imageSrc={project.deployments[0]?.createdBy.avatar}
                  initials={getInitials(
                    project.deployments[0]?.createdBy?.name ?? '',
                  )}
                  className="rounded-full"
                  size={24}
                />
                <span>{project.deployments[0]?.createdBy?.name}</span>
              </div>
            </OverviewInfo>
          </>
        ) : (
          <p className="text-elements-low-em text-sm py-3">
            No current deployment found.
          </p>
        )}
        {project.auctionId && <AuctionCard project={project} />}
      </div>
      <Activity activities={activities} isLoading={fetchingActivities} />
    </div>
  );
};

export default OverviewTabPanel;
