import { useState, useContext, useEffect } from "react";
import NewYorkCaption from "./captionHeaders/newYorkCaption.js";
import NewJerseyCaption from "./captionHeaders/newJerseyCaption.js";
import { useParams } from "react-router-dom";
import { Link, useNavigate } from "react-router-dom";
import EditElement from "../../pageElements/EditElement";
import { db } from "../../firebase";
import {
  collection,
  updateDoc,
  onSnapshot,
  doc,
  getDoc,
  setDoc,
  increment,
} from "firebase/firestore";
import { AppContext } from "../../Hooks/useContext/appContext";

import Button from "../../pageElements/Button";
import ConfirmModal from "../Modals/ConfirmModal";
import LoadingSpinner from "../../pageElements/LoadingSpinner";
import { scrubAll } from "../../Utils/String";
import { docEditCopy } from "../../Constants/Copy/docEditCopy.js";
import "../../styles/docedit-page.scss";

const DocEditPage = () => {
  const { documentId, responseGenerations, caseId, documentType } = useParams();
  const navigate = useNavigate();
  const [parsedRogs, setParsedRogs] = useState();
  const [responses, setResponses] = useState([1]);
  const [fetchedCase, setFetchedCase] = useState();
  const [showInputEle, setShowInputEle] = useState(true);
  const [document, setDocument] = useState(null);
  const { appState } = useContext(AppContext);
  const { group } = appState;
  const appUserId = group ? group.appUserId : null;
  const [docId, setDocId] = useState(documentId);
  const [saveDocumentId, setSaveDocumentId] = useState("");
  const [showSaveModal, setShowSaveModal] = useState(false);
  const [isLoading, setIsLoading] = useState(false);
  const [isReport, setIsReport] = useState(false);
  const [issueText, setIssueText] = useState("");
  const [responsesCreated, setResponsesCreated] = useState(
    parseInt(responseGenerations)
  );
  const [index, setIndex] = useState(0);

  // For document generation:
  const state = group ? group?.state : null;
  const lawFirm = group ? group?.firm : null;
  const streetAdd = group ? group?.streetAddress : null;
  const city = group ? group.city : null;
  const usState = group ? group.state : null;
  const zipCode = group ? group.zipCode : null;
  const telephone = group ? group.telephone : null;

  const apiUrl =
    process.env.NODE_ENV === "development"
      ? process.env.REACT_APP_API_DEV
      : process.env.REACT_APP_API_PROD;

  const displayCopy =
    state === "New York"
      ? docEditCopy.NewYork
      : state === "New Jersey"
      ? docEditCopy.NewJersey
      : docEditCopy.NewYork;

  const headerPicker = () => {
    switch (state) {
      case "New York":
        return (
          <NewYorkCaption
            displayCopy={displayCopy}
            fetchedCase={fetchedCase}
            onScrollClick={onScrollClick}
          />
        );
      case "New Jersey":
        return (
          <NewJerseyCaption
            displayCopy={displayCopy}
            fetchedCase={fetchedCase}
            onScrollClick={onScrollClick}
          />
        );
      default:
        return (
          <NewYorkCaption
            displayCopy={displayCopy}
            fetchedCase={fetchedCase}
            onScrollClick={onScrollClick}
          />
        );
    }
  };

  const headerString =
    documentType === "interrogatories" ? (
      "Response to Interrogatories"
    ) : documentType === "admissions" ? (
      "Response to Request for Admissions"
    ) : documentType === "production" ? (
      "Response to Request for Production"
    ) : documentType === "combined-numbered" ? (
      "Response to Interrogatories and Request for Production"
    ) : (
      <></>
    );

  const servingParty =
    fetchedCase?.clientPosition === "Defendant"
      ? fetchedCase?.plaintiffParties
      : fetchedCase?.defendantParties;

  const messages = [
    "Generating responses. Please be patient, this may take several minutes.",
  ];

  /*
   *  GET docuement data from Firebase
   * */

  useEffect(() => {
    if (!appUserId || !docId) {
      setDocument(null);
      return;
    }
    try {
      getCase(caseId);
      getDocument();
    } catch (err) {
      console.log("Error:", err);
    }
  }, [appUserId, docId, caseId]);

  /*
   *   GET parsed requests.
   *   GET completions if already generated
   * */
  useEffect(() => {
    if (!documentId || !documentType) {
      return;
    }
    // TODO: possible *BUG*  sometimes sends network req to gen repsonses after first (maybe state is not updating?)
    getParsedRequests(documentId, documentType);
    if (responsesCreated > 0) {
      getCompletions(documentId)
        .then((data) => {
          const resp = data[0].responses.map((item, index) => {
            // NEVER CHANGE THIS:
            return { showInputEle: false, resp: item.text, index: index };
          });
          setResponses(resp);
        })
        .catch((err) => console.log(err));
    }
  }, [documentId]);

  /*
   *   If response completions = 0, generate responses
   */

  useEffect(() => {
    if (responsesCreated > 0) {
      return;
    }
    if (responsesCreated < 1) {
      if (documentType == "combined-numbered") {
        try {
          const res = generateResponsesCombined(documentId);
        } catch (err) {
          console.log(err);
        }
      } else {
        try {
          const res = generateResponses(documentId);
        } catch (err) {
          console.log(err);
        }
      }
    }
  }, [responsesCreated, documentId]);

  async function getCase(parentCaseId) {
    try {
      const docRef = doc(db, "cases", `${parentCaseId}`);
      const docSnap = await getDoc(docRef);
      if (docSnap.exists()) {
        const _case = docSnap.data();
        _case.id = docSnap._key.path.segments[1];
        setFetchedCase(_case);
      } else {
        console.log("DB item does not exist");
      }
    } catch (error) {
      console.log(`A system error has occurred: ${error}`);
    }
  }

  function getDocument() {
    const docRef = doc(db, "documents", `${docId}`);
    const unsub = onSnapshot(docRef, (snapshot) => {
      if (snapshot.exists() && snapshot.data().ownerId === appUserId) {
        setDocument({ ...snapshot.data(), documentId: snapshot.id });
      } else {
        setDocument(null);
      }
    });
    return unsub;
  }

  async function getParsedRequests(documentId) {
    if (documentId) {
      const docType = String(documentType);
      try {
        const response = await fetch(
          `${apiUrl}/getParsedRequests/${documentId}/${docType}`,
          {
            method: "GET",
          }
        );
        const res = await response.json();

        const req = res[0].requests;
        if (req.length > 1) {
          setParsedRogs(req);
        }
      } catch (err) {
        console.log("Error occured:", err);
      }
    }
  }

  async function getCompletions(docId) {
    const docType = String(documentType);
    const response = await fetch(`${apiUrl}/completions/${docId}/${docType}`, {
      method: "GET",
    });
    const req = await response.json();
    return req;
  }

  async function generateResponsesCombined(documentId) {
    if (responsesCreated > 0) {
      return;
    }
    const docType = String(documentType);
    let mode;
    //TODO: remove isRequests var if not goign to use
    const isRequests = false;
    console.log(
      "generateResponsesCombined docmentId docType",
      documentId,
      docType
    );
    try {
      setIsLoading(true);
      fetch(
        `${apiUrl}/genResponseFromArrayCombined/${documentId}/${docType}/${isRequests}`,
        {
          method: "GET",
        }
      )
        .then(function (response) {
          return response.json();
        })
        .then((data) => {
          const respArray = data[0].responses;
          const result = respArray?.map((item, index) => {
            let obj = {};
            obj["showInputEle"] = false;
            obj["resp"] = item.text;
            obj["index"] = index;
            return obj;
          });
          setResponses(result);
          updateRespGenerationCount(documentId);
          setIsLoading(false);
        })
        .catch((err) => console.log(err));
    } catch (err) {
      console.log("err", err);
    }
  }

  async function generateResponses(documentId) {
    if (responsesCreated > 0) {
      return;
    }
    const docType = String(documentType);
    let mode;
    //TODO: remove isRequests var
    const isRequests = false;

    try {
      setIsLoading(true);
      fetch(
        `${apiUrl}/genResponseFromArray/${documentId}/${docType}/${isRequests}`,
        {
          method: "GET",
        }
      )
        .then(function (response) {
          return response.json();
        })
        .then((data) => {
          const respArray = data[0].responses;
          const result = respArray?.map((item, index) => {
            let obj = {};
            obj["showInputEle"] = false;
            obj["resp"] = item.text;
            obj["index"] = index;
            return obj;
          });
          setResponses(result);
          updateRespGenerationCount(documentId);
          setIsLoading(false);
        })
        .catch((err) => console.log(err));
    } catch (err) {
      console.log("err", err);
    }
  }

  async function postEditedResponses() {
    let obj = {};
    obj["type"] = documentType;
    obj["id"] = docId;
    obj["requests"] = responses;
    const data = JSON.stringify(obj);
    try {
      const response = await fetch(`${apiUrl}/storecompletions`, {
        method: "POST",
        headers: { "Content-Type": "application/json" },
        json: true,
        body: data,
      });
      const res = response;
      return res;
    } catch (error) {
      console.error("Error sending responses to the server:", error);
    }
  }

  async function createAndReturnDocx() {
    const response = await handleCreateDocx();
    if (response.status === 200) {
      setTimeout(getDocx, 5000);
      setTimeout(cleanUpDocx, 10000);
    }
  }

  async function cleanUpDocx() {
    const docId = documentId;
    const reqType = documentType;
    fetch(`${apiUrl}/cleanUpDocx/${docId}/${reqType}`, {
      method: "GET",
    })
      .then((response) => {
        console.log(response);
      })
      .catch((err) => {
        console.log(err);
      });
  }

  async function getDocx() {
    const docId = documentId;
    const reqType = documentType;
    fetch(`${apiUrl}/getDocx/${docId}/${reqType}`, {
      method: "GET",
    }).then((response) => {
      response.blob().then((blob) => {
        let url = window.URL.createObjectURL(blob);
        let a = window.document.createElement("a");
        a.href = url;
        a.download = `${reqType}-repsonse.docx`;
        a.click();
      });
    });
  }

  async function handleCreateDocx() {
    // TODO: compare to see if any changes made before gen, save those
    const docId = documentId;
    const leadAttorneys = fetchedCase?.leadAttorneys
      ? fetchedCase?.leadAttorneys
      : null;
    const reqType = documentType;
    const captionOne = fetchedCase.caption;
    const captionTwo = fetchedCase.captionTwo;
    const caseNum = fetchedCase.caseNumber;
    const plaintiffs = fetchedCase.plaintiffParties;
    const defendants = fetchedCase.defendantParties;
    const venued = fetchedCase.venue;
    const juris = fetchedCase.jurisdiction;
    const judge = fetchedCase.judge;
    const clientPosition = fetchedCase?.clientPosition
      ? fetchedCase?.clientPosition
      : null;

    try {
      const response = await fetch(`${apiUrl}/genDocx/${docId}/${reqType}`, {
        method: "POST",
        headers: {
          Accept: "application/json",
          "Content-Type": "application/json",
        },
        body: JSON.stringify({
          caseCaption1: captionOne,
          caseCaption2: captionTwo,
          caseNumber: caseNum,
          clientPosition: clientPosition,
          defendant: defendants,
          firm: lawFirm,
          firmCity: city,
          firmState: usState,
          firmStreetAddress: streetAdd,
          firmZip: zipCode,
          judge: judge,
          jurisdiction: juris,
          leadAttorneys: leadAttorneys,
          plaintiff: plaintiffs,
          state: usState,
          tel: telephone,
          venue: venued,
        }),
      });
      return response;
    } catch (error) {
      console.error("Error sending responses to the server:", error);
    }
  }

  async function updateRespGenerationCount(docId) {
    await updateDoc(doc(db, "documents", docId), {
      responseGenerations: increment(1),
    });
    setResponsesCreated((responsesCreated) => responsesCreated + 1);
  }

  function saveDocument(documentId) {
    setSaveDocumentId(documentId);
    setShowSaveModal(!showSaveModal);
  }

  async function postEditedResponses() {
    let obj = {};

    obj["type"] = "INTERROGATORY";
    obj["id"] = docId;
    obj["requests"] = responses;
    const data = JSON.stringify(obj);
    try {
      const response = await fetch(`${apiUrl}/storeeditedcompletions`, {
        method: "POST",
        headers: { "Content-Type": "application/json" },
        json: true,
        body: data,
      });
      const res = response;
      return res;
    } catch (error) {
      console.error("Error sending responses to the server:", error);
    }
  }

  const handleBlur = (e, i) => {
    const newSelectedResponses = responses?.map((r) => {
      if (r.index === i) {
        return {
          ...r,
          showInputEle: !showInputEle,
        };
      }
      return r;
    });
    setResponses(newSelectedResponses);
  };

  const handleFocus = (arg, i) => {
    const newSelectedResponses = responses?.map((r) => {
      if (r.index === i) {
        return {
          ...r,
          showInputEle: !showInputEle,
        };
      }
      return r;
    });
    setResponses(newSelectedResponses);
  };

  const handleEditValue = (e, i) => {
    const editingRes = responses?.map((r) => {
      if (r.index === i) {
        return {
          ...r,
          resp: e.target.value,
        };
      }
      return r;
    });
    setResponses(editingRes);
  };

  const handleBack = () => {
    navigate(`/documents`);
  };

  const handleCancelSave = () => {
    setShowSaveModal(false);
  };

  const handleSave = () => {
    postEditedResponses();
    setShowSaveModal(false);
  };

  const handleConfirmSave = () => {
    setShowSaveModal(true);
  };

  const handleReport = () => {
    setShowSaveModal(false);
    setIsReport(false);
  };

  const handleConfirmReport = () => {
    setShowSaveModal(true);
    setIsReport(true);
  };

  async function reportDoc() {
    const data = {
      documentId: documentId,
      caseId: caseId,
      appUserId: appUserId,
      issueDescription: issueText,
    };
    try {
      const reportRef = collection(db, "supportrequests");
      await setDoc(doc(reportRef, documentId), data);
    } catch (err) {
      console.log("Error saving case to db:", err);
    }
  }

  const onScrollClick = () => {
    const bottom = window.document.scrollingElement.scrollHeight;
    const place = window.scrollY;
    if (place > bottom / 2) {
      window.scrollTo({ top: 0, behavior: "smooth" });
    } else if (place < bottom / 2) {
      window.scrollTo({ top: bottom, behavior: "smooth" });
    }
  };

  const numberingContent = (i) => {
    let numText;
    if (documentType === "interrogatories") {
      numText = "INTERROGATORY NO..";
    } else if (documentType === "admissions") {
      numText = "REQUEST FOR ADMISSION NO.";
    } else if (documentType === "production") {
      numText = "REQUEST FOR PRODUCTION NO.";
    } else {
      numText = "REQUEST NO.";
    }
    return <div className="numbering-container">{`${numText}${i + 1}  `}</div>;
  };

  const respondent =
    fetchedCase?.clientPosition == "Defendant"
      ? fetchedCase?.defendantParties
      : fetchedCase?.plaintiffParties;

  const fooBar =
    fetchedCase?.clientPosition == "Defendant"
      ? fetchedCase?.plaintiffParties
      : fetchedCase?.defendantParties;

  const editingContent = () => {
    return (
      <>
        <div> {headerPicker()}</div>
        <div className="doc-editing-wrapper">
          <div className="pleading-header">{headerString}</div>
          <div>
            {displayCopy.prelimaryStatement(
              documentType,
              respondent,
              servingParty
            )}
          </div>
          <div className="doc-editing-sub-wrapper">
            {parsedRogs?.map((rog, i) => (
              <div className="req-item-outer-div">
                <div className="request-text-up">
                  {numberingContent(i)}
                  {rog?.text}
                </div>
                <div className="req-item-inner-div">
                  <EditElement
                    value={
                      responses && responses.length > 2
                        ? // NEVER CHANGE THIS
                          responses[i].resp
                        : null
                    }
                    setShowInputEle={setShowInputEle}
                    showInputEle={
                      responses && responses.length > 2
                        ? responses[i].showInputEle
                        : null
                    }
                    handleFocus={handleFocus}
                    handleEditValue={handleEditValue}
                    handleBlur={handleBlur}
                    i={i}
                  />
                </div>
              </div>
            ))}
            <div
              className="docedit-report-container"
              onClick={() => handleConfirmReport()}
            >
              <div className="docedit-report-link">Report an issue</div>
            </div>
            <div className="doc-editing-button-container">
              <div className="generate-button-box">
                {/*  TODO: add tooltip: "This will save the document and create a .docx file that will (be downloaded?  saved somewhere?" */}
                <Button
                  className="primary-button create-gen-button"
                  onClick={createAndReturnDocx}
                  labelText={"Create .docx File"}
                />
              </div>
              <div className="details-button-box">
                <div>
                  <Button
                    className="pt-2 pb-2 mr-4 secondary-button edit-back-button"
                    onClick={handleBack}
                    labelText="Back To Documents Page"
                  />
                </div>
                <div>
                  <Button
                    className="pt-2 pb-2 mr-2 primary-button"
                    onClick={handleConfirmSave}
                    labelText="Save Changes"
                  />
                </div>
              </div>
            </div>
          </div>
        </div>
        {showSaveModal && !isReport && documentId !== null ? (
          <ConfirmModal
            onCancel={handleCancelSave}
            onConfirm={handleSave}
            buttonLabelText="Confirm Save"
            modalText={
              "Are you sure?  This will overrwrite any previously-saved edits."
            }
          />
        ) : null}
        {showSaveModal && isReport && documentId !== null ? (
          <ConfirmModal
            isReport={isReport}
            onCancel={handleCancelSave}
            onConfirm={handleReport}
            buttonLabelText="Report Issue"
            documentId={documentId}
            caseId={caseId}
            appUserId={appUserId}
            issuetext={issueText}
            setIssueText={setIssueText}
            modalText={
              "Date/time and document id automatically logged. Support will address this within 24 hours."
            }
          />
        ) : null}
      </>
    );
  };

  const readyToEdit = fetchedCase && responses.length > 1;

  return isLoading ? (
    <LoadingSpinner message={messages[0]} />
  ) : readyToEdit ? (
    editingContent()
  ) : (
    <div className="docedit-errstate-container">
      <div className="nodocs-text-container">
        <p>
          {" "}
          Response content for this document cannot be displayed at this time.
        </p>
        <p>Support has been notified and will respond within 24 hours.</p>
        <Link to="/dashboard">Return to Dashboard</Link>
      </div>
    </div>
  );
};

export default DocEditPage;
