import styled from '@emotion/styled';
import { useMutation, useQuery } from '@tanstack/react-query';
import { Field, Form, Formik } from 'formik';
import { useCallback, useEffect, useState } from 'react';
import { green300, green500, red300, red500 } from '../../next-res/colors';
import { AdminButton, AdminWrapper, InteractiveDate, JSONDisplay } from '../../next-res/components/admin/common';
import { NavbarPage, NavigationBar } from '../../next-res/components/admin/NavBar';
import { useSearchParams, useRouter, usePathname } from 'next/navigation';

const Section = styled.div`
  padding: 20px;
  border: 1px solid #eee;
  border-radius: 5px;
  margin-bottom: 20px;
`;

const Table = styled.table`
  width: 100%;
  tbody {
    tr:nth-of-type(odd) {
      background-color: #f9f9f9;
    }
    tr {
      transition: background-color 0.3s;
      cursor: pointer;
    }
    tr:hover {
      background-color: #f1f1f1;
    }
  }
  td,
  th {
    padding: 5px 10px;
  }

  td {
    span.pill {
      padding: 4px 10px;
      border-radius: 5px;
      font-size: 0.7em;
      font-weight: bold;
      text-transform: uppercase;
    }
    .enabled {
      color: white;
      background-color: ${green500};
    }
    .disabled {
      color: white;
      background-color: ${red500};
    }
  }
`;

const SyncDetailRow = styled.div`
  display: flex;
  gap: 10px;
  flex-direction: row;
  margin-bottom: 10px;
  width: 100%;
  position: relative;
`;
const SyncDetailTitle = styled.span`
  font-weight: bold;
`;

const SyncDetailValue = styled.span``;

const DangerZone = styled.div`
  background-color: #fffefe;
  padding: 20px;
  border: 1px solid ${red500};
  border-radius: 5px;
  margin-top: 40px;

  h2 {
    margin: 10px 0;
    color: ${red300};
  }
  > p {
    margin: 10px 0;
    color: ${red300};
  }
`;

const HideShowFormButton = styled.button`
  width: 100%;
  padding: 7px 20px;
  border: none;
  background-color: #eee;
  cursor: pointer;
  transition: background-color 0.3s ease;
  &:hover {
    background-color: #ddd;
  }
  margin-bottom: 20px;
`;

const Hider = styled.div`
  transition: all 0.4s ease;
  overflow: hidden;
`;
const GetAccessTokenForm = styled(Form)`
  label {
    display: flex;
    flex-direction: column;
    width: 100%;
    margin: 10px 0;
    input {
      padding: 10px;
      border: 1px solid #ddd;
      border-radius: 5px;
    }
  }
`;

const ZohoSync = ({ serverUri }: { serverUri: string }) => {
  const [showAddForm, setShowAddForm] = useState(false);
  const [showControls, setShowControls] = useState(true);
  const [showRecentTokens, setShowRecentTokens] = useState(false);
  const [accessTokenSuccess, setAccessTokenSuccess] = useState(false);

  const searchParams = useSearchParams();
  const router = useRouter();
  const pathname = usePathname();

  // Get search param for syncId
  const syncId = searchParams.get('syncId');
  useEffect(() => {
    if (syncId) {
      setSelectedSyncId(parseInt(syncId));
    }
  }, [syncId]);

  const {
    mutate: getAccessToken,
    isLoading: isGettingAccessToken,
    isError: getAccessTokenError,
    error: getAccessTokenErrorData,
  } = useMutation(async (values: { clientId: string; clientSecret: string; code: string }) => {
    console.log(values);
    let params = new URLSearchParams({
      client_id: values.clientId,
      client_secret: values.clientSecret,
      grant_type: 'authorization_code',
      code: values.code,
    });
    let url = `${serverUri}/api/admin/zoho/token?${params.toString()}`;
    let response = await fetch(url, {
      method: 'POST',
    });

    if (!response.ok) {
      throw new Error(`${JSON.stringify(await response.json())}`);
    }
    setAccessTokenSuccess(true);
    return response.json() as any;
  });

  const {
    mutate: refreshAccessToken,
    isLoading: isRefreshingAccessToken,
    isError: isRefreshAccessTokenError,
  } = useMutation(async () => {
    let url = `${serverUri}/api/admin/zoho/token/refresh`;
    let response = await fetch(url, {
      method: 'POST',
    });

    if (!response.ok) {
      throw new Error(`${JSON.stringify(await response.json())}`);
    }
    return response.json() as any;
  });

  const {
    data: recentTokens,
    isLoading: isRecentTokensLoading,
    isError: isRecentTokensError,
  } = useQuery({
    queryKey: ['zohoTokens'],
    queryFn: async () => {
      const response = await fetch(`${serverUri}/api/admin/zoho/recentTokens`, { credentials: 'include' });
      if (!response.ok) {
        throw new Error(await response.text());
      }
      const data = await response.json();
      return data.data;
    },
  });

  const {
    data: latestEngagementSync,
    isLoading: isLatestEngagementSyncLoading,
    isError: isLatestEngagementSyncError,
    refetch: refetchLatestEngagementSync,
  } = useQuery({
    queryKey: ['zohoLatestEngagementSync'],
    queryFn: async () => {
      const response = await fetch(`${serverUri}/api/admin/zoho/latestEngagementScoreSync`, { credentials: 'include' });
      console.log(response);
      console.log(response.ok);
      if (!response.ok) {
        throw new Error(await response.text());
      }

      const data = await response.json();
      return data?.latest_sync;
    },
  });

  const {
    mutate: syncEngagementScores,
    isLoading: isSyncingEngagementScores,
    isError: isSyncingengagementScoreError,
  } = useMutation(async () => {
    let url = `${serverUri}/api/admin/zoho/syncEngagementScore`;
    let response = await fetch(url, {
      method: 'POST',
    });

    if (!response.ok) {
      throw new Error(`${JSON.stringify(await response.json())}`);
    }
    return response.json() as any;
  });

  // Get recent syncs
  const {
    data: recentSyncs,
    isLoading: isRecentSyncsLoading,
    isError: isRecentSyncsError,
  } = useQuery({
    queryKey: ['zohoRecentSyncs'],
    queryFn: async () => {
      const response = await fetch(`${serverUri}/api/admin/zoho/recentSyncs`, { credentials: 'include' });
      if (!response.ok) {
        throw new Error(await response.text());
      }
      const data = await response.json();
      return data.data;
    },
  });

  // Get specific sync info
  const [selectedSyncId, setSelectedSyncId] = useState<number | null>(null);
  const {
    data: syncDetail,
    isLoading: isSyncDetailLoading,
    isError: isSyncDetailError,
  } = useQuery({
    queryKey: ['zohoSyncDetail', selectedSyncId],
    queryFn: async () => {
      if (!selectedSyncId) {
        return null;
      }
      const response = await fetch(`${serverUri}/api/admin/zoho/syncStatus/${selectedSyncId}`, {
        credentials: 'include',
      });
      if (!response.ok) {
        throw new Error(await response.text());
      }
      const data = await response.json();
      return data.data;
    },
  });

  const getLastCharacters = useCallback((str: string, n: number) => {
    return '*****' + str.slice(str.length - n);
  }, []);
  return (
    <AdminWrapper>
      <h1 style={{ marginBottom: '20px' }}>Zoho Sync Status</h1>
      <NavigationBar currentPage={NavbarPage.ZohoSync} />

      <p>This page allows you to check the sync status of the users to the Zoho crm.</p>

      <HideShowFormButton
        onClick={() => {
          setShowControls((prev) => !prev);
        }}
      >
        {showControls ? 'Hide' : 'Show Zoho Sync Controls'}
      </HideShowFormButton>
      <Hider
        style={{
          maxHeight: showControls ? '500px' : '0',
          opacity: showControls ? 1 : 0,
        }}
      >
        <Section>
          <h3>Zoho Sync Controls</h3>

          <p>
            This will sync the top 5000 users' last 28 day engagement scores to Zoho.
            <br />
            Engagement scores under 1 will not be synced to Zoho to save on API calls.
            <br />
            Go to the{' '}
            <a target="_blank" href="/admin/dashboards?page=engaged-users">
              Engaged Users dashboard
            </a>{' '}
            to see a more detailed list of user engagement activity
          </p>
          <div
            style={{
              display: 'flex',
              gap: '10px',
              alignItems: 'center',
            }}
          >
            <AdminButton
              disabled={isSyncingEngagementScores}
              onClick={() => {
                if (!isSyncingEngagementScores) syncEngagementScores();
              }}
            >
              {isSyncingEngagementScores ? 'Syncing Engagement Score to Zoho' : 'Sync Engagement Score to Zoho'}
            </AdminButton>

            <small>
              Last synced:{' '}
              {isLatestEngagementSyncLoading ? (
                'Loading...'
              ) : isLatestEngagementSyncError ? (
                'Error loading sync'
              ) : latestEngagementSync ? (
                <InteractiveDate date={latestEngagementSync} />
              ) : (
                'Never'
              )}
            </small>
          </div>
        </Section>
      </Hider>
      <Section>
        <div
          style={{
            display: 'flex',
            gap: '30px',
          }}
        >
          <div>
            <div style={{ marginBottom: '10px' }}>
              <h3>Recent Syncs</h3>
            </div>
            <div>
              <p>These are the last 20 syncs to Zoho, including any manual syncs</p>
            </div>
            {isRecentSyncsLoading && <p>Loading...</p>}
            {isRecentSyncsError && <p>Error loading syncs</p>}
            {recentSyncs && recentSyncs.length === 0 && <p>No recent syncs found</p>}
            {recentSyncs && recentSyncs.length > 0 && (
              <Table>
                <thead>
                  <tr>
                    <th>ID</th>
                    <th>Synced At</th>
                    <th>Sync Type</th>
                    <th>Users Affected</th>
                    <th>Sync Status</th>
                  </tr>
                </thead>
                <tbody>
                  {recentSyncs.map((sync: any, i: number) => (
                    <tr
                      key={i}
                      onClick={() => {
                        setSelectedSyncId(sync.id);
                        // Set the syncId in the URL
                        const current = new URLSearchParams(Array.from(searchParams.entries()));
                        current.set('syncId', sync.id.toString());
                        router.push(`${pathname}?${current.toString()}`);
                      }}
                    >
                      <td>{sync.id}</td>
                      <td>
                        <InteractiveDate date={sync.created_at} />
                      </td>
                      <td>{sync.sync_type}</td>
                      <td>{sync.user_ids ? sync?.user_ids?.length : 1}</td>
                      <td>{sync.sync_status}</td>
                    </tr>
                  ))}
                </tbody>
              </Table>
            )}
          </div>
          <div
            style={{
              width: '400px',
              display: 'flex',
              flexDirection: 'column',
              flexGrow: 1,
            }}
          >
            <h3>Sync Detail {syncId && `for ID: ${syncId}`}</h3>
            {isSyncDetailLoading && <p>Loading...</p>}
            {isSyncDetailError && <p>Error loading sync detail</p>}
            {syncDetail && (
              <>
                <SyncDetailRow>
                  <SyncDetailTitle>Sync ID</SyncDetailTitle>
                  <SyncDetailValue>{syncDetail.id}</SyncDetailValue>
                </SyncDetailRow>
                <SyncDetailRow>
                  <SyncDetailTitle>Synced At</SyncDetailTitle>
                  <SyncDetailValue>
                    <InteractiveDate date={syncDetail.created_at} />
                  </SyncDetailValue>
                </SyncDetailRow>
                <SyncDetailRow>
                  <SyncDetailTitle>User ID(s)</SyncDetailTitle>
                  <SyncDetailValue>
                    {syncDetail.user_id ? (
                      <a href={`/admin/user/${syncDetail.user_id}`}>{syncDetail.user_id}</a>
                    ) : (
                      syncDetail.user_ids?.map((id: number) => (
                        <>
                          <a key={id} href={`/admin/user/${id}`}>
                            {id}
                          </a>{' '}
                        </>
                      ))
                    )}
                  </SyncDetailValue>
                </SyncDetailRow>
                <SyncDetailRow>
                  <SyncDetailTitle>Users Affected</SyncDetailTitle>
                  <SyncDetailValue>{syncDetail.user_ids ? syncDetail?.user_ids?.length : 1}</SyncDetailValue>
                </SyncDetailRow>
                <SyncDetailRow>
                  <SyncDetailTitle>Sync Status</SyncDetailTitle>
                  <SyncDetailValue>{syncDetail.sync_status}</SyncDetailValue>
                </SyncDetailRow>
                <SyncDetailTitle>Error</SyncDetailTitle>
                <JSONDisplay
                  style={{
                    width: '100%',
                    whiteSpace: 'pre-wrap',
                    wordWrap: 'break-word',
                  }}
                  json={syncDetail.error_message}
                />
              </>
            )}
          </div>
        </div>
      </Section>

      <DangerZone>
        <h2>Authentication Zone</h2>
        <p>Used only for debuggnig purposes.</p>
        <HideShowFormButton
          onClick={() => {
            setShowAddForm((prev) => !prev);
          }}
        >
          {showAddForm ? 'Hide' : 'Get a new Access Token'}
        </HideShowFormButton>
        <Hider
          style={{
            maxHeight: showAddForm ? '500px' : '0',
            opacity: showAddForm ? 1 : 0,
          }}
        >
          <Section>
            <h3>Get Access Token</h3>
            <p>Use this form to get the initial access and refresh token.</p>
            <p>
              You will need the client id, client secret, and a code.
              <br />
              You can get these from the Zoho API console.
              <a href="https://api-console.zoho.com/" target="_blank">
                Zoho API Console
              </a>
            </p>
            <p>
              You can find a list of scopes here:{' '}
              <a href="https://www.zoho.com/crm/developer/docs/api/v3/scopes.html" target="_blank">
                Zoho Scopes
              </a>
            </p>
            <Formik
              initialValues={{
                clientId: '',
                clientSecret: '',
                code: '',
              }}
              onSubmit={async (values) => {
                getAccessToken(values);
              }}
            >
              <GetAccessTokenForm>
                <label>
                  Client Id:
                  <Field type="text" name="clientId" placeholder="1000.xxxxxxxxxxxxxxxxx" />
                </label>
                <label>
                  Client Secret:
                  <Field type="text" name="clientSecret" placeholder="xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" />
                </label>
                <label>
                  Code:
                  <Field type="text" name="code" placeholder="1000.xxxxxxxxxxxxx.xxxxxxxxxxxxxx" />
                </label>
                <div style={{ display: 'flex', gap: '5px' }}>
                  <AdminButton type="submit">Get and Save Access Token</AdminButton>
                  {isGettingAccessToken && <div>Loading...</div>}
                  {getAccessTokenError && (
                    <div style={{ color: red500 }}>
                      Error getting access token: {(getAccessTokenErrorData as any)?.message}
                    </div>
                  )}
                  {accessTokenSuccess && (
                    <div style={{ color: green300 }}>Access token gotten successfully, please refresh the page</div>
                  )}
                </div>
              </GetAccessTokenForm>
            </Formik>
          </Section>
        </Hider>

        <HideShowFormButton
          onClick={() => {
            setShowRecentTokens((prev) => !prev);
          }}
        >
          {showRecentTokens ? 'Hide' : 'Show Recent Tokens'}
        </HideShowFormButton>
        <Hider
          style={{
            maxHeight: showRecentTokens ? '1000px' : '0',
            opacity: showRecentTokens ? 1 : 0,
          }}
        >
          <Section>
            <div
              style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center', marginBottom: '10px' }}
            >
              <h3>Recent Tokens</h3>
              <AdminButton
                onClick={() => {
                  refreshAccessToken();
                }}
              >
                {isRefreshingAccessToken
                  ? 'Refreshing...'
                  : isRefreshAccessTokenError
                  ? 'Error'
                  : 'Refresh Access Token'}
              </AdminButton>
            </div>
            <div>
              <p>These are the last 10 access tokens for the Zoho API.</p>
            </div>
            {isRecentTokensLoading && <p>Loading...</p>}
            {isRecentTokensError && <p>Error loading tokens</p>}
            {recentTokens && recentTokens.length === 0 && <p>No recent tokens found</p>}
            {recentTokens && recentTokens.length > 0 && (
              <Table>
                <thead>
                  <tr>
                    <th>Valid</th>
                    <th>Created</th>
                    <th>Expiry</th>
                    <th>Access Token</th>
                    <th>Refresh Token</th>
                  </tr>
                </thead>
                <tbody>
                  {recentTokens.map((token: any, i: number) => (
                    <tr key={i}>
                      <td>
                        <span className={`pill ${token.is_valid ? 'enabled' : 'disabled'}`}>
                          {token.is_valid ? 'Valid' : 'Expired'}
                        </span>
                      </td>
                      <td>
                        <InteractiveDate date={token.created_at} />
                      </td>
                      <td>
                        <InteractiveDate date={token.expires_at} />
                      </td>
                      <td>
                        <span>{getLastCharacters(token.access_token, 7)}</span>
                      </td>
                      <td>
                        <span>{getLastCharacters(token.refresh_token, 7)}</span>
                      </td>
                    </tr>
                  ))}
                </tbody>
              </Table>
            )}
          </Section>
        </Hider>
      </DangerZone>
    </AdminWrapper>
  );
};

export async function getServerSideProps(context: any) {
  const serverUri = process.env.SERVER_URI || 'http://localhost:3001';

  // Get the user's session based on the request
  if (context?.req?.user?.role !== 'admin') {
    context.res.statusCode = 404;
    context.res.end();
  }

  return {
    props: { serverUri },
  };
}

export default ZohoSync;
