/**
 *
 * Copyright 2023-2024 InspectorRAGet Team
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
 **/

'use client';

import { isEmpty } from 'lodash';
import { useMemo, useState, useEffect } from 'react';
import { Tag, Tooltip } from '@carbon/react';
import { AddComment } from '@carbon/icons-react';

import { Model, TaskCommentProvenance, TaskEvaluation } from '@/src/types';
import { useDataStore } from '@/src/store';
import { extractMouseSelection } from '@/src/utilities/selectors';
import { useNotification } from '@/src/components/notification/Notification';
import TaskTile from '@/src/components/task-tile/TaskTile';
import AddCommentModal from '@/src/components/comments/AddCommentModal';
import ViewComments from '@/src/components/comments/CommentsViewer';
import RAGTask from '@/src/views/task/RAGTask';
import TextGenerationTask from '@/src/views/task/TextGenerationTask';

import classes from './Task.module.scss';

// ===================================================================================
//                                TYPES
// ===================================================================================
interface Props {
  taskId: string;
  onClose: Function;
}

// ===================================================================================
//                               HELPER FUNCTIONS
// ===================================================================================
/**
 * Update existing provenance
 * @param component reference location
 * @param setCommentProvenance function to update state variable
 * @param createNotification function to notify user of any issues with selection
 */
function updateCommentProvenance(
  component: string,
  setCommentProvenance: Function,
  createNotification: Function,
) {
  try {
    const [text, offsets] = extractMouseSelection();
    if (text !== '') {
      setCommentProvenance({
        component: component,
        text: text,
        offsets: offsets,
      });
    }
  } catch (err) {
    // Notify user
    createNotification({
      kind: 'error',
      title: 'Invalid selection',
      subtitle: 'cannot select text from different part of the page.',
    });

    // Reset selection
    setCommentProvenance(undefined);
  }
}

// ===================================================================================
//                               MAIN FUNCTION
// ===================================================================================
export default function Task({ taskId, onClose }: Props) {
  // Step 1: Initialize state and necessary variables
  const [addCommentModalOpen, setAddCommentModalOpen] =
    useState<boolean>(false);
  const [taskCopierModalOpen, setTaskCopierModalOpen] =
    useState<boolean>(false);
  const [commentProvenance, setCommentProvenance] = useState<
    TaskCommentProvenance | undefined
  >(undefined);

  // Step 2: Run effects
  // Step 2.a: Notification hook
  const { createNotification } = useNotification();

  // Step 2.b: Handle task close event
  useEffect(() => {
    const handleEsc = (event) => {
      // If "Escape" key is pressed
      if (event.key === 'Escape') {
        // Step 1: Close task view
        onClose();

        // Step 2: Stop event propogation
        event.preventDefault();
      }
    };
    window.addEventListener('keydown', handleEsc);

    return () => {
      window.removeEventListener('keydown', handleEsc);
    };
  }, []);

  // Step 2.c: Fetch data from data store
  const { item: data, taskMap, updateTask } = useDataStore();

  // Step 2.d: Configure model's map and metrics
  const [models, metrics] = useMemo(() => {
    if (data) {
      // Step 2.d.i: Make model_id -> model_name map
      const modelsMap = new Map<string, Model>(
        data.models.map((model) => [model.modelId, model]),
      );

      return [modelsMap, data.metrics];
    }

    // Default return
    return [undefined, undefined];
  }, [data?.models, data?.metrics]);

  // Step 2.e: Fetch task
  const task = useMemo(() => {
    if (taskMap && taskId) {
      return taskMap.get(taskId);
    }
  }, [taskId, taskMap]);

  // Step 2.f: Initialize comment viewer status
  const [showComments, setShowComments] = useState<boolean>(
    (task?.comments?.length && task.comments.length > 0) || false,
  );

  // Step 2.g: Fetch evaluations for the current task
  const evaluations = useMemo(() => {
    let taskEvaluations: TaskEvaluation[] | undefined = undefined;
    if (data) {
      taskEvaluations = data.evaluations.filter(
        (evaluation) => evaluation.taskId === taskId,
      );
    }

    return taskEvaluations;
  }, [taskId, task?.contexts, data?.documents, data?.evaluations]);

  // Step 3: Render
  return (
    <div className={classes.page}>
      <AddCommentModal
        open={addCommentModalOpen}
        selectedText={commentProvenance ? commentProvenance.text : undefined}
        onSubmit={(comment: string, author: string) => {
          // Step 1: Create comment to add
          const commentToAdd = {
            comment: comment,
            author: author,
            created: Date.now(),
            updated: Date.now(),
            provenance: commentProvenance,
          };

          // Step 2: Add comment to task
          updateTask(taskId, {
            comments: task?.comments
              ? [...task?.comments, commentToAdd]
              : [commentToAdd],
          });

          // Step 3: Clear provenance
          setCommentProvenance(undefined);

          // Step 4: Close modal
          setAddCommentModalOpen(false);

          // Step 5: Open comments viewer
          setShowComments(true);
        }}
        onClose={() => {
          // Clear provenance
          setCommentProvenance(undefined);

          // Close modal
          setAddCommentModalOpen(false);
        }}
        provenance={commentProvenance}
        models={models}
      ></AddCommentModal>
      <div className={classes.pageHint}>
        <Tag
          type={'outline'}
          onClick={() => {
            onClose();
          }}
        >
          Press 'Escape' to close
        </Tag>
      </div>
      {task && evaluations && (
        <div>
          <TaskTile
            task={task}
            evaluations={evaluations}
            expanded={false}
            onClickFlagIcon={() => {
              // Step 1.a: Update global copy
              updateTask(task.taskId, {
                flagged: !task?.flagged,
              });
            }}
            onClickCommentsIcon={() => {
              setShowComments(!showComments);
            }}
            onClickCopyToClipboardIcon={() => {
              setTaskCopierModalOpen(true);
            }}
          ></TaskTile>
        </div>
      )}
      {task && models && evaluations && (
        <div className={classes.taskContainer}>
          {task.comments && !isEmpty(task.comments) && showComments && (
            <div className={classes.commentsContainer}>
              <ViewComments
                comments={task.comments}
                onUpdate={(updatedComments) => {
                  updateTask(taskId, {
                    comments: updatedComments,
                  });
                }}
                models={models}
              ></ViewComments>
            </div>
          )}
          {task.taskType === 'rag' ? (
            <RAGTask
              task={task}
              models={models}
              metrics={metrics}
              taskCopierModalOpen={taskCopierModalOpen}
              setTaskCopierModalOpen={setTaskCopierModalOpen}
              updateCommentProvenance={(provenance: string) => {
                updateCommentProvenance(
                  provenance,
                  setCommentProvenance,
                  createNotification,
                );
              }}
            />
          ) : task.taskType === 'text_generation' ? (
            <TextGenerationTask
              task={task}
              models={models}
              metrics={metrics}
              taskCopierModalOpen={taskCopierModalOpen}
              setTaskCopierModalOpen={setTaskCopierModalOpen}
              updateCommentProvenance={(provenance: string) => {
                updateCommentProvenance(
                  provenance,
                  setCommentProvenance,
                  createNotification,
                );
              }}
            />
          ) : null}
          <div
            key={'add-comment-btn'}
            tabIndex={0}
            className={classes.addCommentBtn}
            onClick={() => {
              setAddCommentModalOpen(true);
            }}
            onKeyDown={(event) => {
              if (event.key === 'Enter') {
                setAddCommentModalOpen(true);
              }
            }}
          >
            <Tooltip align={'top-right'} label={'Click to add comment'}>
              <AddComment size={20}></AddComment>
            </Tooltip>
          </div>
        </div>
      )}
    </div>
  );
}
