import { useEffect, useState } from 'react';
import { Link, useNavigate, useParams } from 'react-router';

import { Button, Card, Tabs, Typography } from '@material-tailwind/react';
import {
  HiOutlineArrowLeft,
  HiOutlineDownload,
  HiOutlineExternalLink,
  HiOutlineRefresh,
  HiOutlineStop
} from 'react-icons/hi';
import { Prism as SyntaxHighlighter } from 'react-syntax-highlighter';
import {
  materialDark,
  coy
} from 'react-syntax-highlighter/dist/esm/styles/prism';

import AnsiText from '@/components/ui/AppsPage/AnsiText';
import FgDialog from '@/components/ui/Dialogs/FgDialog';
import type { JobFileInfo, FileSharePath } from '@/shared.types';
import JobStatusBadge from '@/components/ui/AppsPage/JobStatusBadge';
import { formatDateString, buildRelaunchPath, parseGithubUrl } from '@/utils';
import {
  getPreferredPathForDisplay,
  makeBrowseLink
} from '@/utils/pathHandling';
import { usePreferencesContext } from '@/contexts/PreferencesContext';
import { useZoneAndFspMapContext } from '@/contexts/ZonesAndFspMapContext';
import {
  useJobQuery,
  useJobFileQuery,
  useCancelJobMutation
} from '@/queries/jobsQueries';

function FilePreview({
  content,
  language,
  isDarkMode
}: {
  readonly content: string | null | undefined;
  readonly language: string;
  readonly isDarkMode: boolean;
}) {
  if (content === undefined) {
    return <Typography className="text-foreground p-4">Loading...</Typography>;
  }

  if (content === null) {
    return (
      <Typography className="text-foreground p-4 italic">
        File not available
      </Typography>
    );
  }

  if (language === 'text') {
    return <AnsiText content={content} isDarkMode={isDarkMode} />;
  }

  const theme = isDarkMode ? materialDark : coy;
  const themeCodeStyles = theme['code[class*="language-"]'] || {};

  return (
    <Card className="overflow-hidden">
      <SyntaxHighlighter
        codeTagProps={{
          style: {
            ...themeCodeStyles,
            paddingBottom: '2em'
          }
        }}
        customStyle={{
          margin: 0,
          padding: '1rem',
          fontSize: '14px',
          lineHeight: '1.5',
          overflow: 'visible',
          width: '100%',
          boxSizing: 'border-box',
          minHeight: 'fit-content'
        }}
        language={language}
        showLineNumbers={false}
        style={theme}
        wrapLines={true}
        wrapLongLines={true}
      >
        {content}
      </SyntaxHighlighter>
    </Card>
  );
}

function FilePathLink({
  fileInfo,
  pathPreference,
  zonesAndFspMap
}: {
  readonly fileInfo: JobFileInfo | undefined;
  readonly pathPreference: ['linux_path' | 'windows_path' | 'mac_path'];
  readonly zonesAndFspMap: Record<string, unknown>;
}) {
  if (!fileInfo?.fsp_name || !fileInfo.subpath) {
    return null;
  }

  // Find the FSP in the zones map to get platform-specific paths
  let fsp: FileSharePath | null = null;
  for (const value of Object.values(zonesAndFspMap)) {
    if (
      value &&
      typeof value === 'object' &&
      'name' in value &&
      (value as FileSharePath).name === fileInfo.fsp_name
    ) {
      fsp = value as FileSharePath;
      break;
    }
  }

  const displayPath = fsp
    ? getPreferredPathForDisplay(pathPreference, fsp, fileInfo.subpath)
    : fileInfo.path;

  const browseUrl = makeBrowseLink(fileInfo.fsp_name, fileInfo.subpath);

  return (
    <Link
      className="text-primary-light text-sm font-mono hover:underline"
      to={browseUrl}
    >
      {displayPath}
    </Link>
  );
}

export default function JobDetail() {
  const { jobId } = useParams<{ jobId: string }>();
  const navigate = useNavigate();
  const [isDarkMode, setIsDarkMode] = useState(false);
  const [activeTab, setActiveTab] = useState('parameters');
  const [showStopConfirm, setShowStopConfirm] = useState(false);

  const { pathPreference } = usePreferencesContext();
  const { zonesAndFspQuery } = useZoneAndFspMapContext();

  const id = jobId ? parseInt(jobId) : 0;
  const jobQuery = useJobQuery(id);
  const jobStatus = jobQuery.data?.status;
  const scriptQuery = useJobFileQuery(id, 'script');
  const stdoutQuery = useJobFileQuery(id, 'stdout', jobStatus);
  const stderrQuery = useJobFileQuery(id, 'stderr', jobStatus);
  const cancelMutation = useCancelJobMutation();

  const isService = jobQuery.data?.entry_point_type === 'service';

  useEffect(() => {
    const checkDarkMode = () => {
      setIsDarkMode(document.documentElement.classList.contains('dark'));
    };
    checkDarkMode();
    const observer = new MutationObserver(checkDarkMode);
    observer.observe(document.documentElement, {
      attributes: true,
      attributeFilter: ['class']
    });
    return () => observer.disconnect();
  }, []);

  const job = jobQuery.data;

  const handleDownload = (content: string, filename: string) => {
    const blob = new Blob([content], { type: 'text/plain' });
    const url = URL.createObjectURL(blob);
    const a = document.createElement('a');
    a.href = url;
    a.download = filename;
    a.click();
    URL.revokeObjectURL(url);
  };

  const handleRelaunch = () => {
    if (!job) {
      return;
    }
    const { owner, repo, branch } = parseGithubUrl(job.app_url);
    const path = buildRelaunchPath(
      owner,
      repo,
      branch,
      job.entry_point_id,
      job.manifest_path || undefined
    );
    navigate(path, {
      state: {
        parameters: job.parameters,
        resources: job.resources,
        env: job.env,
        pre_run: job.pre_run,
        post_run: job.post_run,
        pull_latest: job.pull_latest,
        container: job.container,
        container_args: job.container_args
      }
    });
  };

  return (
    <div>
      <Button
        className="!rounded-md mb-6"
        onClick={() => navigate('/apps/jobs')}
        variant="outline"
      >
        <HiOutlineArrowLeft className="icon-small mr-2" />
        Back to Jobs
      </Button>

      {jobQuery.isPending ? (
        <div className="animate-pulse">
          {/* Title skeleton */}
          <div className="mb-6">
            <div className="w-72 h-6 bg-surface rounded mb-3" />
            <div className="flex items-center gap-4 mt-2">
              <div className="w-20 h-5 bg-surface rounded-full" />
              <div className="w-36 h-4 bg-surface rounded" />
              <div className="w-36 h-4 bg-surface rounded" />
            </div>
          </div>
          {/* Tab bar skeleton */}
          <div className="flex gap-4 py-2 mb-4 border-b border-surface">
            <div className="w-24 h-4 bg-surface rounded" />
            <div className="w-16 h-4 bg-surface rounded" />
            <div className="w-24 h-4 bg-surface rounded" />
            <div className="w-20 h-4 bg-surface rounded" />
          </div>
          {/* Content area skeleton */}
          <div className="mt-4 space-y-2">
            <div className="w-full h-4 bg-surface rounded" />
            <div className="w-3/4 h-4 bg-surface rounded" />
            <div className="w-1/2 h-4 bg-surface rounded" />
          </div>
        </div>
      ) : jobQuery.isError ? (
        <div className="p-3 bg-error/10 rounded text-error text-sm">
          Failed to load job: {jobQuery.error?.message || 'Unknown error'}
        </div>
      ) : job ? (
        <div>
          {/* Job Info Header */}
          <div className="mb-6">
            <div className="flex items-center justify-between">
              <Typography className="font-bold mb-1" type="h5">
                {job.app_name} &mdash; {job.entry_point_name}
              </Typography>
              <Button
                className="!rounded-md"
                onClick={handleRelaunch}
                variant="outline"
              >
                <HiOutlineRefresh className="icon-small mr-2" />
                Relaunch
              </Button>
            </div>
            <div className="flex flex-wrap items-center gap-4 mt-2">
              <JobStatusBadge status={job.status} />
              <Typography className="text-foreground">
                Submitted: {formatDateString(job.created_at)}
              </Typography>
              {job.started_at ? (
                <Typography className="text-foreground">
                  Started: {formatDateString(job.started_at)}
                </Typography>
              ) : null}
              {job.finished_at ? (
                <Typography className="text-foreground">
                  Finished: {formatDateString(job.finished_at)}
                </Typography>
              ) : null}
              {job.exit_code !== null && job.exit_code !== undefined ? (
                <Typography className="text-foreground">
                  Exit code: {job.exit_code}
                </Typography>
              ) : null}
            </div>
          </div>

          {/* Service URL banner */}
          {isService && job.status === 'RUNNING' ? (
            job.service_url ? (
              <div className="mb-4 p-3 flex items-center gap-3 border border-success rounded-lg bg-success/10">
                <span className="relative flex h-3 w-3">
                  <span className="animate-ping absolute inline-flex h-full w-full rounded-full bg-success opacity-75" />
                  <span className="relative inline-flex rounded-full h-3 w-3 bg-success" />
                </span>
                <Typography className="text-foreground flex-1">
                  Service is running at{' '}
                  <a
                    className="text-primary-light hover:underline font-mono"
                    href={job.service_url}
                    rel="noopener noreferrer"
                    target="_blank"
                  >
                    {job.service_url}
                  </a>
                </Typography>
                <Button
                  className="!rounded-md"
                  color="error"
                  disabled={cancelMutation.isPending}
                  onClick={() => setShowStopConfirm(true)}
                  size="sm"
                >
                  <HiOutlineStop className="icon-small mr-1" />
                  {cancelMutation.isPending ? 'Stopping...' : 'Stop Service'}
                </Button>
                <a
                  className="inline-flex items-center gap-1 px-3 py-1.5 text-sm font-medium rounded-md bg-success text-white hover:bg-success/90 transition-colors"
                  href={job.service_url}
                  rel="noopener noreferrer"
                  target="_blank"
                >
                  <HiOutlineExternalLink className="h-4 w-4" />
                  Open Service
                </a>
              </div>
            ) : (
              <div className="mb-4 p-3 flex items-center gap-3 border border-warning rounded-lg bg-warning/10">
                <span className="relative flex h-3 w-3">
                  <span className="animate-ping absolute inline-flex h-full w-full rounded-full bg-warning opacity-75" />
                  <span className="relative inline-flex rounded-full h-3 w-3 bg-warning" />
                </span>
                <Typography className="text-foreground flex-1">
                  Service is starting up...
                </Typography>
                <Button
                  className="!rounded-md"
                  color="error"
                  disabled={cancelMutation.isPending}
                  onClick={() => setShowStopConfirm(true)}
                  size="sm"
                >
                  <HiOutlineStop className="icon-small mr-1" />
                  {cancelMutation.isPending ? 'Stopping...' : 'Stop Service'}
                </Button>
              </div>
            )
          ) : null}

          {/* Stop Service confirmation dialog */}
          <FgDialog
            onClose={() => setShowStopConfirm(false)}
            open={showStopConfirm}
          >
            <Typography className="text-foreground font-bold mb-2" type="h6">
              Stop Service
            </Typography>
            <Typography className="text-foreground mb-4">
              Are you sure you want to stop this service? It will be terminated
              and the URL will no longer be accessible.
            </Typography>
            <div className="flex justify-end gap-2">
              <Button
                className="!rounded-md"
                onClick={() => setShowStopConfirm(false)}
              >
                Cancel
              </Button>
              <Button
                className="!rounded-md"
                color="error"
                disabled={cancelMutation.isPending}
                onClick={() => {
                  cancelMutation.mutate(job.id);
                  setShowStopConfirm(false);
                }}
              >
                <HiOutlineStop className="icon-small mr-1" />
                {cancelMutation.isPending ? 'Stopping...' : 'Stop Service'}
              </Button>
            </div>
          </FgDialog>

          {/* Tabs */}
          <Tabs onValueChange={setActiveTab} value={activeTab}>
            <Tabs.List className="justify-start items-stretch shrink-0 min-w-fit w-full py-2 bg-surface dark:bg-surface-light">
              <Tabs.Trigger
                className="!text-foreground h-full"
                value="parameters"
              >
                Parameters
              </Tabs.Trigger>
              <Tabs.Trigger className="!text-foreground h-full" value="script">
                Script
              </Tabs.Trigger>
              <Tabs.Trigger className="!text-foreground h-full" value="stdout">
                Output Log
              </Tabs.Trigger>
              <Tabs.Trigger className="!text-foreground h-full" value="stderr">
                Error Log
              </Tabs.Trigger>
              <Tabs.TriggerIndicator className="h-full" />
            </Tabs.List>

            <Tabs.Panel className="pt-4" value="parameters">
              {Object.keys(job.parameters).length > 0 ? (
                <Card className="p-3">
                  {Object.entries(job.parameters).map(([key, value]) => (
                    <div className="flex gap-2 py-1" key={key}>
                      <Typography className="text-foreground font-semibold">
                        {key}:
                      </Typography>
                      <Typography className="text-foreground">
                        {String(value)}
                      </Typography>
                    </div>
                  ))}
                </Card>
              ) : (
                <Typography className="text-foreground italic">
                  No parameters
                </Typography>
              )}
            </Tabs.Panel>

            <Tabs.Panel className="pt-4" value="script">
              <div className="flex items-center justify-between mb-2">
                <FilePathLink
                  fileInfo={job.files?.script}
                  pathPreference={pathPreference}
                  zonesAndFspMap={zonesAndFspQuery.data || {}}
                />
              </div>
              <FilePreview
                content={
                  scriptQuery.isPending ? undefined : (scriptQuery.data ?? null)
                }
                isDarkMode={isDarkMode}
                language="bash"
              />
            </Tabs.Panel>

            <Tabs.Panel className="pt-4" value="stdout">
              <div className="flex items-center justify-between mb-2">
                <FilePathLink
                  fileInfo={job.files?.stdout}
                  pathPreference={pathPreference}
                  zonesAndFspMap={zonesAndFspQuery.data || {}}
                />
                {stdoutQuery.data !== undefined && stdoutQuery.data !== null ? (
                  <Button
                    className="!rounded-md"
                    onClick={() =>
                      handleDownload(stdoutQuery.data!, `job-${id}-stdout.log`)
                    }
                    size="sm"
                  >
                    <HiOutlineDownload className="icon-small mr-2" />
                    Download
                  </Button>
                ) : null}
              </div>
              <FilePreview
                content={
                  stdoutQuery.isPending ? undefined : (stdoutQuery.data ?? null)
                }
                isDarkMode={isDarkMode}
                language="text"
              />
            </Tabs.Panel>

            <Tabs.Panel className="pt-4" value="stderr">
              <div className="flex items-center justify-between mb-2">
                <FilePathLink
                  fileInfo={job.files?.stderr}
                  pathPreference={pathPreference}
                  zonesAndFspMap={zonesAndFspQuery.data || {}}
                />
                {stderrQuery.data !== undefined && stderrQuery.data !== null ? (
                  <Button
                    className="!rounded-md"
                    onClick={() =>
                      handleDownload(stderrQuery.data!, `job-${id}-stderr.log`)
                    }
                    size="sm"
                  >
                    <HiOutlineDownload className="icon-small mr-2" />
                    Download
                  </Button>
                ) : null}
              </div>
              <FilePreview
                content={
                  stderrQuery.isPending ? undefined : (stderrQuery.data ?? null)
                }
                isDarkMode={isDarkMode}
                language="text"
              />
            </Tabs.Panel>
          </Tabs>
        </div>
      ) : null}
    </div>
  );
}
