import { useCallback, useEffect, useMemo, useState } from "react";
import { useMutation, useQuery } from "@apollo/client";
import { ADD_JOB_WATCHER, GET_JOB_WATCHERS, REMOVE_JOB_WATCHER } from "../../graphql/jobs.queries.js";
import { connect } from "react-redux";
import { createStructuredSelector } from "reselect";
import { selectBodyshop, selectCurrentUser } from "../../redux/user/user.selectors.js";
import { useSplitTreatments } from "@splitsoftware/splitio-react";
import JobWatcherToggleComponent from "./job-watcher-toggle.component.jsx";
import { useIsEmployee } from "../../utils/useIsEmployee.js";

const mapStateToProps = createStructuredSelector({
  bodyshop: selectBodyshop,
  currentUser: selectCurrentUser
});

function JobWatcherToggleContainer({ job, currentUser, bodyshop }) {
  const {
    treatments: { Enhanced_Payroll }
  } = useSplitTreatments({
    attributes: {},
    names: ["Enhanced_Payroll"],
    splitKey: bodyshop && bodyshop.imexshopid
  });

  const isEmployee = useIsEmployee(bodyshop, currentUser);
  const [open, setOpen] = useState(false);
  const [selectedWatcher, setSelectedWatcher] = useState(null);
  const [selectedTeam, setSelectedTeam] = useState(null);

  const userEmail = currentUser.email;
  const jobid = job.id;

  // Fetch current watchers with refetch capability
  const {
    data: watcherData,
    loading: watcherLoading,
    refetch
  } = useQuery(GET_JOB_WATCHERS, {
    variables: { jobid },
    fetchPolicy: "cache-and-network" // Ensure fresh data from server
  });

  // Refetch jobWatchers when the popover opens (open changes to true)
  useEffect(() => {
    if (open) {
      refetch().catch((err) =>
        console.error(`Something went wrong fetching Notification Watchers on popover open: ${err?.message}`, {
          stack: err?.stack
        })
      );
    }
  }, [open, refetch]);

  const jobWatchers = useMemo(() => (watcherData?.job_watchers ? [...watcherData.job_watchers] : []), [watcherData]);
  const isWatching = jobWatchers.some((w) => w.user_email === userEmail);

  const [addWatcher, { loading: adding }] = useMutation(ADD_JOB_WATCHER, {
    onCompleted: () =>
      refetch().catch((err) =>
        console.error(`Something went wrong fetching Notification Watchers after add: ${err?.message}`, {
          stack: err?.stack
        })
      ),
    onError: (err) => {
      if (err.graphQLErrors && err.graphQLErrors.length > 0) {
        const errorMessage = err.graphQLErrors[0].message;
        if (
          errorMessage.includes("Uniqueness violation") ||
          errorMessage.includes("idx_job_watchers_jobid_user_email_unique")
        ) {
          console.warn("Watcher already exists for this job and user.");
          refetch().catch((err) =>
            console.error(
              `Something went wrong fetching Notification Watchers after uniqueness violation: ${err?.message}`,
              { stack: err?.stack }
            )
          ); // Sync with server to ensure UI reflects actual state
        } else {
          console.error(`Error adding job watcher: ${errorMessage}`);
        }
      } else {
        console.error(`Unexpected error adding job watcher: ${err.message || JSON.stringify(err)}`);
      }
    },
    update(cache, { data }) {
      if (!data || !data.insert_job_watchers_one) {
        console.warn("No data or insert_job_watchers_one returned from mutation, skipping cache update.");
        refetch().catch((err) =>
          console.error(`Something went wrong updating Notification Watchers after add: ${err?.message}`, {
            stack: err?.stack
          })
        );
        return;
      }

      const insert_job_watchers_one = data.insert_job_watchers_one;
      const existingData = cache.readQuery({
        query: GET_JOB_WATCHERS,
        variables: { jobid }
      });

      cache.writeQuery({
        query: GET_JOB_WATCHERS,
        variables: { jobid },
        data: {
          ...existingData,
          job_watchers: [...(existingData?.job_watchers || []), insert_job_watchers_one]
        }
      });
    }
  });

  const [removeWatcher, { loading: removing }] = useMutation(REMOVE_JOB_WATCHER, {
    onCompleted: () =>
      refetch().catch((err) =>
        console.error(`Something went wrong fetching Notification Watchers after remove: ${err?.message}`, {
          stack: err?.stack
        })
      ), // Refetch to sync with server after success
    onError: (err) => console.error(`Error removing job watcher: ${err.message}`),
    update(cache, { data: { delete_job_watchers } }) {
      const existingData = cache.readQuery({
        query: GET_JOB_WATCHERS,
        variables: { jobid }
      });

      const deletedWatcher = delete_job_watchers.returning[0];
      const updatedWatchers = deletedWatcher
        ? (existingData?.job_watchers || []).filter((watcher) => watcher.user_email !== deletedWatcher.user_email)
        : existingData?.job_watchers || [];

      cache.writeQuery({
        query: GET_JOB_WATCHERS,
        variables: { jobid },
        data: {
          ...existingData,
          job_watchers: updatedWatchers
        }
      });
    }
  });

  const handleToggleSelf = useCallback(async () => {
    if (adding || removing || !isEmployee) return;
    if (isWatching) {
      await removeWatcher({ variables: { jobid, userEmail } });
    } else {
      await addWatcher({ variables: { jobid, userEmail } });
    }
  }, [isWatching, addWatcher, removeWatcher, jobid, userEmail, adding, removing, isEmployee]);

  const handleRemoveWatcher = useCallback(
    async (email) => {
      if (removing) return;
      await removeWatcher({ variables: { jobid, userEmail: email } });
    },
    [removeWatcher, jobid, removing]
  );

  const handleWatcherSelect = useCallback(
    async (selectedUser) => {
      if (adding || removing) return;
      const employee = bodyshop.employees.find((e) => e.id === selectedUser);
      if (!employee) return;

      const email = employee.user_email;
      const isAlreadyWatching = jobWatchers.some((w) => w.user_email === email);

      if (isAlreadyWatching) {
        await handleRemoveWatcher(email);
      } else {
        await addWatcher({ variables: { jobid, userEmail: email } });
      }
      setSelectedWatcher(null);
    },
    [jobWatchers, addWatcher, handleRemoveWatcher, jobid, bodyshop, adding, removing]
  );

  const handleTeamSelect = useCallback(
    async (team) => {
      if (adding) return;
      const selectedTeamMembers = JSON.parse(team);
      const newWatchers = selectedTeamMembers.filter(
        (email) => !jobWatchers.some((watcher) => watcher.user_email === email)
      );

      if (newWatchers.length === 0) {
        console.warn("All selected team members are already watchers.");
        setSelectedTeam(null);
        return;
      }
      await Promise.all(
        newWatchers.map((email) =>
          addWatcher({
            variables: {
              jobid,
              userEmail: email
            }
          })
        )
      );
    },
    [jobWatchers, addWatcher, jobid, adding]
  );

  return (
    <JobWatcherToggleComponent
      jobWatchers={jobWatchers}
      isWatching={isWatching}
      watcherLoading={watcherLoading}
      adding={adding}
      removing={removing}
      open={open}
      setOpen={setOpen}
      selectedWatcher={selectedWatcher}
      setSelectedWatcher={setSelectedWatcher}
      selectedTeam={selectedTeam}
      setSelectedTeam={setSelectedTeam}
      bodyshop={bodyshop}
      Enhanced_Payroll={Enhanced_Payroll}
      handleToggleSelf={handleToggleSelf}
      handleRemoveWatcher={handleRemoveWatcher}
      handleWatcherSelect={handleWatcherSelect}
      handleTeamSelect={handleTeamSelect}
      currentUser={currentUser}
      isEmployee={isEmployee} // Pass isEmployee to the component
    />
  );
}

export default connect(mapStateToProps)(JobWatcherToggleContainer);
