import styled from '@emotion/styled';
import { useMutation, useQuery } from '@tanstack/react-query';
import { ErrorMessage, Field, Form, Formik } from 'formik';
import { useEffect, useRef, useState } from 'react';
import { gray800, green500, lightPastelBlue, red500 } from '../../next-res/colors';
import { AdminWrapper, InteractiveDate, Undefined } from '../../next-res/components/admin/common';
import { PlanOverride } from '../../src/types/adminServerTypes';
import { NavbarPage, NavigationBar } from '../../next-res/components/admin/NavBar';

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};
    }
    button {
      padding: 2px 10px;
      margin: 2px 5px;
      width: 100%;
      color: black;
      border: none;
      cursor: pointer;
      transition: background-color 0.3s ease;
      background-color: ${gray800};
      &:hover {
        background-color: ${lightPastelBlue};
      }
    }
  }
  td.emailnote {
    span {
      width: 190px;
    }

    .email {
      font-weight: bold;
      text-overflow: ellipsis;
      display: block;
      overflow: hidden;
      margin: 0;
    }
    .note {
      font-size: 0.8em;
      color: #666;
      white-space: nowrap;
      text-overflow: ellipsis;
      display: block;
      overflow: hidden;
      margin: 0;
    }

    &.open {
      .note {
        white-space: pre-wrap;
      }
    }
  }
`;

const FormikLabel = styled.label`
  display: flex;
  align-items: left;
  flex-direction: column;
  gap: 5px;
  width: 100%;
  margin: 10px 0;

  span.labelArea {
    display: flex;
    justify-content: space-between;
    align-items: center;
    width: 100%;
  }
`;

const FormikForm = styled(Form)`
  display: flex;
  flex-direction: column;
  align-items: center;
  width: 100%;
  button {
    height: 40px;
    padding: 10px 15px;
    background-color: #0070f3;
    color: white;
    border: none;
    cursor: pointer;
  }
`;
const FormikField = styled(Field)`
  padding: 10px;
  margin: 0;
  width: 100%;
`;

export const FormFieldError = styled(ErrorMessage)`
  color: ${red500};
  font-size: 11px;
  font-family: Montreal, 'Helvetica Neue', Helvetica, sans-serif;
`;

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 AddPlanOverrideHider = styled.div`
  transition: all 0.4s ease;
  overflow: hidden;
`;
const AddPlanOverride = styled.div`
  border: 1px solid #eaeaea;
  border-radius: 5px;
  padding: 20px;
  margin: 0 0 20px 0;
`;

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,
    },
  };
}

interface SearchPlanOverridesValue {
  emailQuery?: string;
  includeDisabled?: boolean;
}

const PlanOverrides = ({ serverUri }: { serverUri: string }) => {
  const [planOverrides, setPlanOverrides] = useState<PlanOverride[]>([]);
  const [showAddForm, setShowAddForm] = useState(false);
  const [selectedOverride, setSelectedOverride] = useState<string>('');

  const searchFormRef = useRef<any>();

  useEffect(() => {
    // Needed to set the cookies
    async function getWhoami() {
      await fetch(`${serverUri}/auth/whoami`, { credentials: 'include' });
    }
    getWhoami();
    searchPlanOverrideMutation({});
  }, []);

  const { data: plans } = useQuery({
    queryKey: ['plans'],
    queryFn: async () => {
      const response = await fetch(`${serverUri}/api/admin/plans`, {
        credentials: 'include',
      });
      const data = await response.json();
      return data;
    },
  });

  const {
    mutate: searchPlanOverrideMutation,
    isLoading: planOverrideIsLoading,
    isError: planOverrideIsError,
    isSuccess: planOverrideIsSuccess,
  } = useMutation(async (values: SearchPlanOverridesValue) => {
    let url = `${serverUri}/api/admin/planOverrides?emailQuery=${values.emailQuery || ''}`;
    if (values.includeDisabled) {
      url += '&includeDisabled=true';
    }
    const response = await fetch(url, {
      credentials: 'include',
    });
    const data = await response.json();
    setPlanOverrides(data);
  }, {});

  const { mutate: disablePlanOverride } = useMutation(async (id: string) => {
    fetch(`${serverUri}/api/admin/planOverride/${id}/disable`, {
      method: 'POST',
      credentials: 'include',
    }).then((res) => {
      searchFormRef.current?.submitForm();
    });
  });

  const { mutate: enablePlanOverride } = useMutation(async (id: string) => {
    fetch(`${serverUri}/api/admin/planOverride/${id}/enable`, {
      method: 'POST',
      credentials: 'include',
    }).then((res) => {
      searchFormRef.current?.submitForm();
    });
  });

  const { mutate: updatePlanOverrideNote } = useMutation(async (options: { id: string; note: string }) => {
    const { id, note } = options;
    fetch(`${serverUri}/api/admin/planOverride/${id}/note`, {
      method: 'POST',
      credentials: 'include',
      body: JSON.stringify({ note }),
      headers: {
        'Content-Type': 'application/json',
      },
    }).then((res) => {
      searchFormRef.current?.submitForm();
    });
  });

  return (
    <AdminWrapper>
      <h1
        style={{
          marginBottom: '20px',
        }}
      >
        Plan Overrides
      </h1>

      <NavigationBar currentPage={NavbarPage.PlanOverrides} />

      <p>
        This page allows you to create and manage plan overrides for users. This is useful for giving users free access
        even before they sign up.
      </p>

      <HideShowFormButton
        onClick={() => {
          setShowAddForm((prev) => !prev);
        }}
      >
        {showAddForm ? 'Hide Add Form' : 'Add New Plan Override'}
      </HideShowFormButton>

      <AddPlanOverrideHider
        style={{
          maxHeight: showAddForm ? '400px' : '0',
          opacity: showAddForm ? 1 : 0,
        }}
      >
        <AddPlanOverride>
          <h3>Add New Plan Override</h3>
          {plans ? (
            <Formik
              initialValues={{
                email: '',
                note: '',
                planId: plans[0].id,
                time: '1',
                timeUnit: 'months',
              }}
              onSubmit={async (values) => {
                const payload: any = {
                  email: values.email,
                  planId: values.planId,
                  note: values.note,
                };
                if (values.timeUnit === 'months') {
                  payload.months = values.time;
                } else if (values.timeUnit === 'days') {
                  payload.days = values.time;
                }

                const result = await fetch(`${serverUri}/api/admin/planOverrides`, {
                  method: 'POST',
                  credentials: 'include',
                  body: JSON.stringify(payload),
                  headers: {
                    'Content-Type': 'application/json',
                  },
                });
                if (result.status === 200) {
                  searchFormRef.current?.submitForm();
                  values.email = '';
                } else {
                  alert('Error adding plan override');
                }
              }}
              validateOnBlur={false}
              validate={(values) => {
                const errors: any = {};
                // Check if the email is valid with a simple email regex
                if (!values.email.match(/.+@.+\..+/)) {
                  errors.email = 'Invalid email';
                }
                if (!values.planId) {
                  errors.planId = 'Required';
                }
                if (!values.time) {
                  errors.time = 'Required';
                }
                // Check if the time is a number
                if (isNaN(parseInt(values.time))) {
                  errors.time = 'Must be a number';
                }
                // Check if time is a positive number
                if (parseInt(values.time) <= 0) {
                  errors.time = 'Must be a positive number';
                }
                if (
                  (values.timeUnit === 'months' && parseInt(values.time) > 12 * 10) ||
                  (values.timeUnit === 'days' && parseInt(values.time) > 365 * 10)
                ) {
                  errors.time = "Hey, stop it. That's too much.";
                }

                return errors;
              }}
            >
              {({ isSubmitting }) => (
                <FormikForm>
                  <div
                    style={{
                      display: 'flex',
                      justifyContent: 'space-between',
                      alignItems: 'end',
                      width: '100%',
                      gap: '10px',
                    }}
                  >
                    <FormikLabel htmlFor="email">
                      <span className="labelArea">
                        <span>Email</span>
                        <FormFieldError name="email" component="div" />
                      </span>

                      <FormikField type="text" name="email" id="email" placeholder="Email" />
                    </FormikLabel>
                    <FormikLabel htmlFor="note">
                      <span className="labelArea">
                        <span>Notes</span>
                        <FormFieldError name="note" component="div" />
                      </span>

                      <FormikField type="text" name="note" id="note" placeholder="Notes (optional)" />
                    </FormikLabel>
                  </div>

                  <div
                    style={{
                      display: 'flex',
                      justifyContent: 'space-between',
                      alignItems: 'end',
                      width: '100%',
                      gap: '10px',
                    }}
                  >
                    <FormikLabel htmlFor="email">
                      <span className="labelArea">
                        <div>Plan</div>
                        <FormFieldError name="planId" component="div" />
                      </span>
                      <FormikField as="select" name="planId" id="planId">
                        {plans?.map((plan: any) => {
                          return (
                            <option key={plan.id} value={plan.id}>
                              {plan.name}
                            </option>
                          );
                        })}
                      </FormikField>
                    </FormikLabel>
                    <FormikLabel htmlFor="email">
                      <span className="labelArea">
                        <div>Time to expire</div>
                        <FormFieldError name="time" component="div" />
                      </span>
                      <div
                        style={{
                          display: 'flex',
                          gap: '5px',
                          alignItems: 'center',
                        }}
                      >
                        <FormikField type="number" name="time" placeholder="Time from now" />
                        <FormikField as="select" name="timeUnit" id="timeUnit">
                          <option value="months">Months</option>
                          <option value="days">Days</option>
                        </FormikField>
                      </div>
                    </FormikLabel>
                    <button
                      type="submit"
                      disabled={isSubmitting}
                      style={{
                        marginBottom: '10px',
                      }}
                    >
                      Add
                    </button>
                  </div>
                </FormikForm>
              )}
            </Formik>
          ) : (
            <p>Loading plans...</p>
          )}
        </AddPlanOverride>
      </AddPlanOverrideHider>

      <h3
        style={{
          marginBottom: '10px',
        }}
      >
        Existing Plan Overrides
      </h3>
      <Formik
        innerRef={searchFormRef}
        initialValues={{ emailQuery: '', includeDisabled: false }}
        onSubmit={async (values) => {
          await searchPlanOverrideMutation(values);
        }}
      >
        {({ isSubmitting }) => (
          <FormikForm>
            <div
              style={{
                display: 'flex',
                justifyContent: 'space-between',
                alignItems: 'center',
                width: '100%',
                gap: '10px',
              }}
            >
              <FormikField type="text" name="emailQuery" placeholder="Search by email (leave blank for all)" />
              <label
                htmlFor="includeDisabled"
                style={{
                  display: 'flex',
                  alignItems: 'center',
                  gap: '5px',
                  cursor: 'pointer',
                }}
              >
                Include Disabled
                <FormikField type="checkbox" name="includeDisabled" id="includeDisabled" />
              </label>

              <button type="submit" disabled={isSubmitting}>
                Search
              </button>
            </div>
          </FormikForm>
        )}
      </Formik>
      {planOverrideIsLoading && <p>Loading...</p>}
      {planOverrideIsError && <p>Error</p>}
      {planOverrideIsSuccess && planOverrides.length === 0 && <p>No overrides found</p>}
      {planOverrideIsSuccess && planOverrides.length > 0 && (
        <div
          style={{
            marginTop: '10px',
          }}
        >
          <small
            style={{
              marginBottom: '10px',
              display: 'block',
            }}
          >
            Only 100 results will be shown
          </small>
          <Table>
            <thead>
              <tr>
                <th>ID</th>
                <th>Email</th>
                <th>Plan</th>
                <th>Expires</th>
                <th>User</th>
                <th>Status</th>
                <th>Actions</th>
              </tr>
            </thead>
            <tbody>
              {planOverrides.map((po: any) => {
                return (
                  <tr
                    key={po.id}
                    onClick={() => {
                      setSelectedOverride(po.id);
                    }}
                  >
                    <td>{po.id}</td>
                    <td className={`emailnote ${po.id === selectedOverride ? 'open' : ''}`}>
                      <span className="email">{po.email}</span>
                      <span className="note">{po.note}</span>
                    </td>
                    <td>{po.plan_name}</td>
                    <td>
                      <InteractiveDate date={po.expires_at} />
                    </td>
                    <td>{po.user ? <a href={`/admin/user/${po.user_id}`}>{po.user}</a> : <Undefined />}</td>
                    <td>
                      {po.enabled ? (
                        <span className="pill enabled">Enabled</span>
                      ) : (
                        <span className="pill disabled">Disabled</span>
                      )}
                    </td>
                    <td>
                      {po.enabled ? (
                        <button
                          onClick={() => {
                            if (confirm(`Are you sure you want to disable this plan override for ${po.email}?`)) {
                              disablePlanOverride(po.id);
                            }
                          }}
                        >
                          Disable
                        </button>
                      ) : (
                        <button
                          onClick={() => {
                            if (confirm(`Are you sure you want to enable this plan override for ${po.email}?`)) {
                              enablePlanOverride(po.id);
                            }
                          }}
                        >
                          Enable
                        </button>
                      )}
                      <button
                        onClick={() => {
                          const newNote = prompt('Enter a new note for this plan override', po.note || '');
                          if (newNote === null) return;
                          updatePlanOverrideNote({ id: po.id, note: newNote });
                        }}
                      >
                        Note
                      </button>
                    </td>
                  </tr>
                );
              })}
            </tbody>
          </Table>
        </div>
      )}
    </AdminWrapper>
  );
};

export default PlanOverrides;
