import React, { useEffect, useMemo, useState } from 'react';
import styled from 'styled-components';
import { HiArrowLeft } from 'react-icons/hi';
import { useParams, useNavigate } from 'react-router-dom';
import { isAxiosError } from 'axios';
import { useLocale } from '@/app/providers/LocaleProvider';
import { AppLayout } from '@/shared/components/layout/AppLayout';
import { Button, Card, Spinner } from '@/shared/components/ui';
import { ROUTES } from '@/shared/constants/routes';
import { useTicket } from '@/features/tickets/hooks/useTicket';
import { useTicketReplies } from '@/features/tickets/hooks/useTicketReplies';
import { useTicketNotes } from '@/features/tickets/hooks/useTicketNotes';
import { useTicketMutations } from '@/features/tickets/hooks/useTicketMutations';
import { useTicketCollaboratorMutations } from '@/features/tickets/hooks/useTicketCollaboratorMutations';
import { useTicketRealtime } from '@/features/tickets/hooks/useTicketRealtime';
import { useTicketPresence } from '@/features/tickets/hooks/useTicketPresence';
import { useTicketSla } from '@/features/tickets/hooks/useTicketSla';
import { useTicketFormOptions } from '@/features/tickets/hooks/useTicketFormOptions';
import { validateAttachmentFiles } from '@/features/tickets/constants/attachments';
import { ConversationSection } from '@/features/tickets/components/ConversationSection';
import { NotesSection } from '@/features/tickets/components/NotesSection';
import { TicketActivityTimeline } from '@/features/tickets/components/TicketActivityTimeline';
import { TicketDetailHero } from '@/features/tickets/components/TicketDetailHero';
import { TicketDetailSidebar } from '@/features/tickets/components/TicketDetailSidebar';
import { TicketDependenciesSection } from '@/features/tickets/components/TicketDependenciesSection';
import { TicketDetailSkeleton } from '@/features/tickets/components/TicketDetailSkeleton';
import type { TicketPriorityRef, TicketStatusRef } from '@/features/tickets/types/ticket.types';
import { buildTicketParticipantContext } from '@/features/tickets/utils/ticketParticipantContext';

const Workspace = styled.div`
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(
      ${({ theme }) => theme.layout.sidebarWidthMin},
      ${({ theme }) => theme.layout.sidebarWidthMax}
    );
  gap: ${({ theme }) => theme.layout.cardGap};
  align-items: start;

  @media (max-width: 1024px) {
    grid-template-columns: 1fr;
    gap: ${({ theme }) => theme.spacing[6]};
  }

  @media (max-width: 640px) {
    gap: ${({ theme }) => theme.spacing[6]};
  }
`;

const MainColumn = styled.div`
  display: flex;
  flex-direction: column;
  gap: ${({ theme }) => theme.spacing[5]};
  min-width: 0;
`;

const DescriptionBody = styled.div`
  white-space: pre-wrap;
  text-align: start;
  font-size: ${({ theme }) => theme.typography.fontSize.sm};
  line-height: ${({ theme }) => theme.typography.lineHeight.relaxed};
  color: ${({ theme }) => theme.colors.text.primary};
  margin: 0;
`;

const PanelState = styled.div`
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: ${({ theme }) => theme.spacing[3]};
  padding: ${({ theme }) => theme.spacing[10]} ${({ theme }) => theme.spacing[4]};
  text-align: center;
  color: ${({ theme }) => theme.colors.text.secondary};
`;

const RestrictedNote = styled(Card)`
  text-align: start;
`;

const RestrictedText = styled.p`
  margin: 0;
  font-size: ${({ theme }) => theme.typography.fontSize.sm};
  color: ${({ theme }) => theme.colors.text.secondary};
  line-height: ${({ theme }) => theme.typography.lineHeight.relaxed};
`;

const TicketDetailPage: React.FC = () => {
  const { id } = useParams<{ id: string }>();
  const { t } = useLocale();
  const navigate = useNavigate();
  const ticketQuery = useTicket(id);
  const repliesQuery = useTicketReplies(id);
  const notesQuery = useTicketNotes(id);

  const formOptionsQuery = useTicketFormOptions(ticketQuery.data?.department.id);
  const slaQuery = useTicketSla(id);
  const mutations = useTicketMutations(id ?? '');
  const collaboratorMutations = useTicketCollaboratorMutations(id ?? '');
  const [removingCollaboratorId, setRemovingCollaboratorId] = useState<string | null>(null);

  const [replyContent, setReplyContent] = useState('');
  const [replyFiles, setReplyFiles] = useState<File[]>([]);
  const [replyFileError, setReplyFileError] = useState<string | null>(null);
  const [noteContent, setNoteContent] = useState('');
  const [composerTab, setComposerTab] = useState<'reply' | 'note'>('reply');

  const notesForbidden =
    notesQuery.isError &&
    isAxiosError(notesQuery.error) &&
    notesQuery.error.response?.status === 403;

  useTicketRealtime(id, { subscribeNotes: !notesForbidden });
  const viewers = useTicketPresence(id);

  useEffect(() => {
    const ticket = ticketQuery.data;
    if (!ticket?.is_project_work_item || !ticket.project_id) {
      return;
    }
    navigate(ROUTES.PROJECT_WORK_ITEM(ticket.project_id, ticket.id), { replace: true });
  }, [ticketQuery.data, navigate]);

  const isMutating =
    mutations.updateTicketMutation.isPending ||
    mutations.assignTicketMutation.isPending ||
    mutations.unassignTicketMutation.isPending ||
    mutations.createReplyMutation.isPending ||
    mutations.createNoteMutation.isPending;

  const statusOptions = useMemo((): TicketStatusRef[] => {
    const ticket = ticketQuery.data;
    const statuses = formOptionsQuery.data?.statuses ?? [];
    if (!ticket) {
      return statuses;
    }

    const map = new Map<string, TicketStatusRef>(statuses.map((status) => [status.id, status]));
    map.set(ticket.status.id, ticket.status);
    return Array.from(map.values());
  }, [formOptionsQuery.data?.statuses, ticketQuery.data]);

  const priorityOptions = useMemo((): TicketPriorityRef[] => {
    const ticket = ticketQuery.data;
    const priorities = formOptionsQuery.data?.priorities ?? [];
    if (!ticket) {
      return priorities;
    }

    const map = new Map<string, TicketPriorityRef>(
      priorities.map((priority) => [priority.id, priority]),
    );
    map.set(ticket.priority.id, ticket.priority);
    return Array.from(map.values());
  }, [formOptionsQuery.data?.priorities, ticketQuery.data]);

  const categoryOptions = formOptionsQuery.data?.categories ?? [];

  const handleReplyFilesChange = (files: File[]) => {
    setReplyFiles(files);
    setReplyFileError(validateAttachmentFiles(files));
  };

  const handleReplySubmit = async () => {
    const content = replyContent.trim();
    if ((!content && replyFiles.length === 0) || replyFileError) return;

    await mutations.createReplyMutation.mutateAsync({
      content,
      attachments: replyFiles,
    });
    setReplyContent('');
    setReplyFiles([]);
  };

  const handleNoteSubmit = async () => {
    const content = noteContent.trim();
    if (!content) return;
    await mutations.createNoteMutation.mutateAsync(content);
    setNoteContent('');
  };

  if (ticketQuery.isLoading) {
    return (
      <AppLayout>
        <TicketDetailSkeleton />
      </AppLayout>
    );
  }

  if (ticketQuery.isError || !ticketQuery.data || !id) {
    return (
      <AppLayout>
        <PanelState role="alert">
          <p>
            {ticketQuery.error instanceof Error
              ? ticketQuery.error.message
              : t('tickets:states.errorDetail')}
          </p>
          <Button variant="primary" onClick={() => ticketQuery.refetch()}>
            {t('tickets:states.retry')}
          </Button>
        </PanelState>
      </AppLayout>
    );
  }

  const ticket = ticketQuery.data;
  const participantContext = buildTicketParticipantContext(ticket);

  return (
    <AppLayout>
      <TicketDetailHero
        ticket={ticket}
        sla={slaQuery.data ?? null}
        viewers={viewers}
        actions={
          <Button
            variant="outline"
            size="sm"
            icon={<HiArrowLeft aria-hidden />}
            onClick={() => navigate(ROUTES.TICKETS)}
          >
            {t('common:actions.back')}
          </Button>
        }
      />

      <Workspace>
        <MainColumn>
          <Card variant="muted" padding="lg" header={t('tickets:detail.description')}>
            <DescriptionBody>{ticket.description}</DescriptionBody>
          </Card>

          <TicketDependenciesSection ticketId={ticket.id} />

          {notesForbidden ? (
            <RestrictedNote variant="muted" padding="lg">
              <RestrictedText>{t('tickets:detail.notesRestricted')}</RestrictedText>
            </RestrictedNote>
          ) : (
            <>
              {notesQuery.isLoading ? (
                <PanelState role="status">
                  <Spinner />
                </PanelState>
              ) : notesQuery.isError ? (
                <PanelState role="alert">
                  <p>{t('tickets:states.errorNotes')}</p>
                  <Button variant="outline" onClick={() => notesQuery.refetch()}>
                    {t('tickets:states.retry')}
                  </Button>
                </PanelState>
              ) : (
                <NotesSection notes={notesQuery.data ?? []} participantContext={participantContext} />
              )}
            </>
          )}

          <ConversationSection
            replies={repliesQuery.data ?? []}
            participantContext={participantContext}
            threadLoading={repliesQuery.isLoading}
            threadError={repliesQuery.isError}
            onRetryThread={() => repliesQuery.refetch()}
            composer={{
                variant: composerTab,
                showTabs: true,
                showNoteTab: !notesForbidden,
                onVariantChange: setComposerTab,
                value: composerTab === 'reply' ? replyContent : noteContent,
                onChange: composerTab === 'reply' ? setReplyContent : setNoteContent,
                onSubmit: () =>
                  void (composerTab === 'reply' ? handleReplySubmit() : handleNoteSubmit()),
                onCancel: () => {
                  if (composerTab === 'reply') {
                    setReplyContent('');
                    setReplyFiles([]);
                    setReplyFileError(null);
                  } else {
                    setNoteContent('');
                  }
                },
                loading:
                  composerTab === 'reply'
                    ? mutations.createReplyMutation.isPending
                    : mutations.createNoteMutation.isPending,
                files: composerTab === 'reply' ? replyFiles : [],
                onFilesChange: composerTab === 'reply' ? handleReplyFilesChange : undefined,
                fileError: composerTab === 'reply' ? replyFileError : null,
              }}
          />

          <TicketActivityTimeline
            statusHistory={ticket.status_history ?? []}
            collaboratorActivity={ticket.collaborator_activity ?? []}
            assignments={ticket.assignments ?? []}
          />
        </MainColumn>

        <TicketDetailSidebar
          ticket={ticket}
          statuses={statusOptions}
          priorities={priorityOptions}
          categories={categoryOptions}
          sla={slaQuery.data}
          slaLoading={slaQuery.isLoading}
          slaError={slaQuery.isError}
          isUpdating={isMutating}
          onStatusChange={(statusId) =>
            mutations.updateTicketMutation.mutate({ status_id: statusId })
          }
          onPriorityChange={(priorityId) =>
            mutations.updateTicketMutation.mutate({ priority_id: priorityId })
          }
          onCategoryChange={(nextCategoryId, nextSubcategoryId) =>
            mutations.updateTicketMutation.mutate({
              category_id: nextCategoryId,
              subcategory_id: nextSubcategoryId,
            })
          }
          onAssign={(assigneeId) =>
            mutations.assignTicketMutation.mutate({ assignee_id: assigneeId })
          }
          onUnassign={() => mutations.unassignTicketMutation.mutate()}
          onAddCollaborator={async (userId) => {
            await collaboratorMutations.addCollaborator({ user_id: userId });
          }}
          onRemoveCollaborator={async (userId) => {
            setRemovingCollaboratorId(userId);
            try {
              await collaboratorMutations.removeCollaborator(userId);
            } finally {
              setRemovingCollaboratorId(null);
            }
          }}
          isAddingCollaborator={collaboratorMutations.isAdding}
          removingCollaboratorId={removingCollaboratorId}
        />
      </Workspace>
    </AppLayout>
  );
};

export default TicketDetailPage;
