import React, { useCallback, useEffect, useState } from "react";

import {
  Alert, Box, Button, Chip, Divider, IconButton, MenuItem, Paper, Skeleton, Stack, TextField,
  Tooltip, Typography,
} from "@mui/material";
import OpenInNewIcon from "@mui/icons-material/OpenInNew";
import RestoreIcon from "@mui/icons-material/Restore";

import { getApiErrorMessage } from "../api";
import {
  ApplicationCv, CoverLetter, TailoringPlan, applicationAssetsApi,
} from "../applicationWorkspace";

// Phase 5.4 — Application Assets sections for the workspace.
//
// These compose systems that already exist. CV editing, preview, PDF export, themes and version
// history all live in the CV builder at /cv-builder — this section only chooses WHICH variant the
// application uses and links out. The cover letter is the one thing genuinely owned here, because it
// is application-specific by nature. docs/architecture/application-workspace.md.

function useAsset<T>(load: () => Promise<T>, deps: React.DependencyList) {
  const [data, setData] = useState<T | null>(null);
  const [error, setError] = useState<string | null>(null);
  const [loading, setLoading] = useState(true);

  // eslint-disable-next-line react-hooks/exhaustive-deps
  const run = useCallback(load, deps);

  const reload = useCallback(() => {
    let cancelled = false;
    setLoading(true);
    run()
      .then((r) => {
        if (!cancelled) {
          setData(r);
          setError(null);
        }
      })
      .catch((err) => {
        if (!cancelled) setError(getApiErrorMessage(err, "Could not load this section."));
      })
      .finally(() => {
        if (!cancelled) setLoading(false);
      });
    return () => {
      cancelled = true;
    };
  }, [run]);

  useEffect(() => reload(), [reload]);

  return { data, error, loading, setData, setError, reload };
}

function Shell({ title, subtitle, loading, error, children }: {
  title: string;
  subtitle?: string;
  loading: boolean;
  error: string | null;
  children: React.ReactNode;
}) {
  return (
    <Paper sx={{ p: { xs: 2, sm: 2.5 }, borderRadius: 3 }}>
      <Typography variant="subtitle2" sx={{ fontWeight: 800 }}>{title}</Typography>
      {subtitle && <Typography variant="caption" color="text.secondary">{subtitle}</Typography>}
      <Divider sx={{ my: 1.5 }} />
      {loading ? (
        <Stack spacing={1}>{[0, 1, 2].map((i) => <Skeleton key={i} variant="rounded" height={44} />)}</Stack>
      ) : error ? (
        <Alert severity="error">{error}</Alert>
      ) : (
        children
      )}
    </Paper>
  );
}

// ---------- CV ----------

export function ApplicationCvSection({ jobId }: { jobId: number }) {
  const { data, error, loading, setData, setError } = useAsset<ApplicationCv>(
    () => applicationAssetsApi.cv(jobId),
    [jobId],
  );
  const [busy, setBusy] = useState(false);

  const attach = async (variantId: number | null) => {
    setBusy(true);
    try {
      setData(await applicationAssetsApi.attachVariant(jobId, variantId));
      setError(null);
    } catch (err) {
      setError(getApiErrorMessage(err, "Could not change the attached CV."));
    } finally {
      setBusy(false);
    }
  };

  const attached = data?.attachedVariantId ?? "";

  return (
    <Stack spacing={2}>
      <Shell
        title="CV"
        subtitle="Which CV variant this application uses. Variants are lenses over your master career profile."
        loading={loading}
        error={error}
      >
        <Stack spacing={2}>
          {(data?.availableVariants.length ?? 0) === 0 ? (
            <Alert severity="info" sx={{ borderRadius: 2 }}>
              No CV variants yet. Build one in the CV builder — it starts from your master career
              profile, so you never retype your history.
            </Alert>
          ) : (
            <TextField
              select
              size="small"
              fullWidth
              label="Attached CV variant"
              value={attached}
              disabled={busy}
              onChange={(e) => attach(e.target.value === "" ? null : Number(e.target.value))}
              helperText="Changing this only re-points the application. The variant itself is untouched."
            >
              <MenuItem value="">None</MenuItem>
              {(data?.availableVariants ?? []).map((v) => (
                <MenuItem key={v.id} value={v.id}>
                  {v.name} · {v.themeId} · v{v.version}
                </MenuItem>
              ))}
            </TextField>
          )}

          {data?.attachedVariantId ? (
            <Paper variant="outlined" sx={{ p: 1.5, borderRadius: 2 }}>
              <Stack direction="row" justifyContent="space-between" alignItems="center" flexWrap="wrap" gap={1}>
                <Box>
                  <Typography variant="body2" sx={{ fontWeight: 700 }}>{data.attachedVariantName}</Typography>
                  <Typography variant="caption" color="text.secondary">
                    Theme {data.attachedThemeId} · version {data.attachedVersion}
                    {data.attachedIsPublic ? " · public" : ""}
                  </Typography>
                </Box>
                <Stack direction="row" spacing={1}>
                  <Button
                    size="small"
                    variant="outlined"
                    endIcon={<OpenInNewIcon fontSize="small" />}
                    // The builder's real route. It loads the variant from :id and enforces ownership
                    // server-side, so there is no second CV loading path here.
                    href={`/career/builder/${data.attachedVariantId}`}
                  >
                    Edit, preview and export
                  </Button>
                </Stack>
              </Stack>
            </Paper>
          ) : (
            <Typography variant="body2" color="text.secondary">
              No CV attached to this application yet.
            </Typography>
          )}

          {data?.hasTailoredCvText && (
            <Alert severity="info" sx={{ borderRadius: 2 }}>
              This application also has legacy tailored CV text saved on it. A CV variant supersedes it.
            </Alert>
          )}
        </Stack>
      </Shell>

      <ApplicationTailoringSection jobId={jobId} />
    </Stack>
  );
}

// ---------- Tailoring ----------

export function ApplicationTailoringSection({ jobId }: { jobId: number }) {
  const { data, error, loading } = useAsset<TailoringPlan>(
    () => applicationAssetsApi.tailoring(jobId),
    [jobId],
  );

  return (
    <Shell
      title="Tailoring"
      subtitle="What to emphasise for this advert. Suggestions only — nothing here edits your profile or your CV."
      loading={loading}
      error={error}
    >
      <Stack spacing={2}>
        {data && !data.hasCareerProfile && (
          <Alert severity="info" sx={{ borderRadius: 2 }}>
            Build your career profile to get experience and project suggestions.
          </Alert>
        )}
        {data && !data.hasJobDescription && (
          <Alert severity="info" sx={{ borderRadius: 2 }}>
            Paste the advert text to get keyword and requirement suggestions.
          </Alert>
        )}

        {(data?.suggestions.length ?? 0) === 0 ? (
          <Typography variant="body2" color="text.secondary">
            Nothing to suggest yet.
          </Typography>
        ) : (
          (data?.suggestions ?? []).map((s) => (
            <Box key={s.kind}>
              <Typography variant="body2" sx={{ fontWeight: 700 }}>{s.title}</Typography>
              {s.detail && (
                <Typography variant="caption" color="text.secondary">{s.detail}</Typography>
              )}
              <Stack direction="row" flexWrap="wrap" gap={0.5} sx={{ mt: 0.75 }}>
                {s.items.map((item) => (
                  <Chip key={item} size="small" label={item} variant="outlined" />
                ))}
              </Stack>
            </Box>
          ))
        )}
      </Stack>
    </Shell>
  );
}

// ---------- Cover letter ----------

const TEMPLATE = `Dear Hiring Manager,

I am writing to apply for the [role] position at [company]. [One sentence on why this company, specifically.]

In my current role I [the most relevant thing you have done, with a concrete outcome]. [A second example that matches what the advert asks for.]

[Why you want this job, in your own words.]

I would welcome the chance to talk it through.

Kind regards,
[Your name]`;

export function ApplicationCoverLetterSection({ jobId }: { jobId: number }) {
  const { data, error, loading, setData, setError } = useAsset<CoverLetter>(
    () => applicationAssetsApi.coverLetter(jobId),
    [jobId],
  );
  const [draft, setDraft] = useState<string | null>(null);
  const [busy, setBusy] = useState(false);

  // The textarea is only seeded from the server until the user starts typing, so a reload never
  // clobbers unsaved edits.
  const text = draft ?? data?.text ?? "";
  const dirty = draft !== null && draft !== (data?.text ?? "");

  const save = async (value: string, source = "manual") => {
    setBusy(true);
    try {
      setData(await applicationAssetsApi.saveCoverLetter(jobId, value, source));
      setDraft(null);
      setError(null);
    } catch (err) {
      setError(getApiErrorMessage(err, "Could not save the cover letter."));
    } finally {
      setBusy(false);
    }
  };

  const restore = async (version: number) => {
    setBusy(true);
    try {
      setData(await applicationAssetsApi.restoreCoverLetter(jobId, version));
      setDraft(null);
      setError(null);
    } catch (err) {
      setError(getApiErrorMessage(err, "Could not restore that version."));
    } finally {
      setBusy(false);
    }
  };

  return (
    <Stack spacing={2}>
      <Shell
        title="Cover letter"
        subtitle="Every save keeps the previous text, so nothing you write is ever lost."
        loading={loading}
        error={error}
      >
        <Stack spacing={2}>
          <TextField
            multiline
            minRows={12}
            fullWidth
            label="Cover letter"
            value={text}
            disabled={busy}
            onChange={(e) => setDraft(e.target.value)}
            placeholder="Write it yourself, start from the template, or generate a draft with the AI panel below."
          />

          <Stack direction="row" spacing={1} flexWrap="wrap" useFlexGap>
            <Button variant="contained" disabled={busy || !dirty} onClick={() => save(text)}>
              Save
            </Button>
            <Button disabled={busy || !dirty} onClick={() => setDraft(null)}>
              Discard changes
            </Button>
            <Button
              disabled={busy || text.trim().length > 0}
              onClick={() => setDraft(TEMPLATE)}
            >
              Start from template
            </Button>
            {dirty && (
              <Chip size="small" color="warning" variant="outlined" label="Unsaved changes" />
            )}
          </Stack>
        </Stack>
      </Shell>

      <Shell title="Version history" loading={loading} error={null}>
        {(data?.versions.length ?? 0) === 0 ? (
          <Typography variant="body2" color="text.secondary">
            No versions yet. The first save starts the history.
          </Typography>
        ) : (
          <Stack spacing={0.5}>
            {(data?.versions ?? []).map((v) => (
              <Stack
                key={v.version}
                direction="row"
                alignItems="center"
                justifyContent="space-between"
                sx={{ py: 0.5 }}
              >
                <Box sx={{ minWidth: 0 }}>
                  <Stack direction="row" spacing={0.75} alignItems="center" flexWrap="wrap">
                    <Typography variant="body2" sx={{ fontWeight: 600 }}>v{v.version}</Typography>
                    <Chip size="small" variant="outlined" label={v.aiAction ? `${v.source} · ${v.aiAction}` : v.source} />
                    {v.isCurrent && <Chip size="small" color="primary" variant="outlined" label="Current" />}
                  </Stack>
                  <Typography variant="caption" color="text.secondary">
                    {new Date(v.createdAtUtc).toLocaleString()} · {v.length} characters
                  </Typography>
                </Box>
                {!v.isCurrent && (
                  <Tooltip title="Restore this version">
                    <span>
                      <IconButton
                        size="small"
                        disabled={busy}
                        aria-label={`Restore version ${v.version}`}
                        onClick={() => restore(v.version)}
                      >
                        <RestoreIcon fontSize="small" />
                      </IconButton>
                    </span>
                  </Tooltip>
                )}
              </Stack>
            ))}
          </Stack>
        )}
      </Shell>
    </Stack>
  );
}
