import {
  mdiCheckCircleOutline,
  mdiCloudUploadOutline,
  mdiContentCopy,
  mdiFileDocumentEditOutline,
  mdiLightbulbOnOutline,
  mdiMicrophoneOutline,
  mdiStopCircleOutline,
  mdiSendOutline,
  mdiTrashCanOutline,
} from '@mdi/js';
import axios from 'axios';
import Head from 'next/head';
import { useRouter } from 'next/router';
import React from 'react';
import type { ReactElement } from 'react';
import BaseIcon from '../components/BaseIcon';
import SectionMain from '../components/SectionMain';
import { getPageTitle } from '../config';
import LayoutAuthenticated from '../layouts/Authenticated';

type Client = {
  id: string;
  name: string;
  ai_processing_consent_granted?: boolean;
  recording_consent_granted?: boolean;
};

type MemoryDraft = {
  title?: string;
  ai_summary?: string;
  key_topics?: string;
  goals_discussed?: string;
  blockers?: string;
  commitments?: string;
  homework?: string;
  emotional_themes?: string;
  important_quotes?: string;
  follow_up_email?: string;
  next_session_prep?: string;
  private_coach_notes?: string;
  shared_client_notes?: string;
};

type Session = MemoryDraft & {
  id: string;
  status?: string;
  client?: Client;
  session_at?: string;
  transcript_notes?: string;
  audio_url?: string;
  audio_filename?: string;
  audio_mime_type?: string;
  audio_size?: number;
};

type AudioAttachment = {
  audio_url: string;
  audio_filename?: string;
  audio_mime_type?: string;
  audio_size?: number;
};

type TranscriptionResult = AudioAttachment & {
  text?: string;
  transcription_chunks?: number;
};

type TranscriptionJob = {
  status: 'queued' | 'processing' | 'completed' | 'failed';
  message?: string;
  chunk_index?: number;
  chunks_total?: number;
  result?: TranscriptionResult;
  error?: unknown;
};

type TranscriptionProgress = {
  current: number;
  total: number;
};

type TranscriptTurn = {
  speaker: string;
  text: string;
};

const MAX_AUDIO_FILE_BYTES = 200 * 1024 * 1024;
const DIRECT_TRANSCRIPTION_FILE_BYTES = 24 * 1024 * 1024;
const ACTIVE_TRANSCRIPTION_JOB_KEY = 'coaching-active-transcription-job-id';

function Panel({
  children,
  className = '',
}: {
  children: React.ReactNode;
  className?: string;
}) {
  return (
    <section
      className={`rounded-none border border-[#19192d]/10 bg-white ${className}`}
    >
      {children}
    </section>
  );
}

function TextField({
  label,
  value,
  onChange,
  rows = 3,
}: {
  label: string;
  value: string;
  onChange: (value: string) => void;
  rows?: number;
}) {
  return (
    <label className='block'>
      <span className='text-xs font-semibold uppercase tracking-[0.18em] text-[#147568]'>
        {label}
      </span>
      <textarea
        value={value}
        rows={rows}
        onChange={(event) => onChange(event.target.value)}
        className='mt-2 w-full rounded-none border border-[#19192d]/10 bg-[#fffdf9] px-4 py-3 text-sm leading-6 text-[#19192d] outline-none focus:border-[#147568] focus:ring-2 focus:ring-[#147568]/15'
      />
    </label>
  );
}

function StatusPill({ status }: { status?: string }) {
  const isShared = status === 'shared';

  return (
    <span
      className={`rounded-none px-3 py-1 text-xs font-semibold ${
        isShared ? 'bg-[#fffdf9] text-[#147568]' : 'bg-[#fffdf9] text-[#147568]'
      }`}
    >
      {isShared ? 'Shared' : 'Coach draft'}
    </span>
  );
}

function formatFileSize(bytes: number) {
  return `${Math.round(bytes / 1024 / 1024)} MB`;
}

function audioTooLargeMessage() {
  return `Audio file is too large. Maximum supported size is ${formatFileSize(
    MAX_AUDIO_FILE_BYTES,
  )}.`;
}

function wait(milliseconds: number) {
  return new Promise((resolve) => setTimeout(resolve, milliseconds));
}

function requestErrorMessage(error: unknown, fallback: string) {
  if (!axios.isAxiosError(error)) {
    return fallback;
  }

  const data = error.response?.data;

  if (error.response?.status === 413 || data?.error === 'payload_too_large') {
    return audioTooLargeMessage();
  }

  if (typeof data?.message === 'string') {
    return data.message;
  }

  if (typeof data?.error === 'string') {
    return data.error;
  }

  if (typeof data?.error?.message === 'string') {
    return data.error.message;
  }

  return fallback;
}

function parseTranscriptTurns(value?: string) {
  const turns: TranscriptTurn[] = [];

  String(value || '')
    .split('\n')
    .map((line) => line.trim())
    .filter(Boolean)
    .forEach((line) => {
      const match = line.match(/^([A-ZА-Я][\wА-Яа-я -]{0,30}):\s*(.+)$/u);

      if (match) {
        turns.push({
          speaker: match[1],
          text: match[2],
        });
        return;
      }

      const previousTurn = turns[turns.length - 1];
      if (previousTurn) {
        previousTurn.text = `${previousTurn.text} ${line}`;
        return;
      }

      turns.push({
        speaker: 'Transcript',
        text: line,
      });
    });

  return turns;
}

function TranscriptConversation({
  value,
  maxTurns,
}: {
  value?: string;
  maxTurns?: number;
}) {
  const turns = parseTranscriptTurns(value);
  const visibleTurns = maxTurns ? turns.slice(0, maxTurns) : turns;

  if (turns.length === 0) {
    return (
      <p className='rounded-none border border-dashed border-[#19192d]/10 bg-[#fffdf9] p-4 text-sm text-[#5f6675]'>
        No transcript saved for this session.
      </p>
    );
  }

  return (
    <div className='space-y-3'>
      {visibleTurns.map((turn, index) => (
        <div
          key={`${turn.speaker}-${index}-${turn.text.slice(0, 18)}`}
          className='grid gap-3 border border-[#19192d]/10 bg-[#fffdf9] p-4 md:grid-cols-[72px_1fr]'
        >
          <div className='text-xs font-semibold uppercase tracking-[0.18em] text-[#147568]'>
            {turn.speaker}
          </div>
          <p className='text-sm leading-6 text-[#19192d]'>{turn.text}</p>
        </div>
      ))}
      {maxTurns && turns.length > maxTurns && (
        <p className='text-sm font-semibold text-[#5f6675]'>
          {turns.length - maxTurns} more transcript turns
        </p>
      )}
    </div>
  );
}

function displayDateTime(value?: string) {
  if (!value) {
    return 'No date';
  }

  const date = new Date(value);
  if (Number.isNaN(date.getTime())) {
    return value;
  }

  return date.toLocaleString(undefined, {
    month: 'short',
    day: 'numeric',
    hour: 'numeric',
    minute: '2-digit',
  });
}

const emptyDraft: MemoryDraft = {
  title: '',
  ai_summary: '',
  key_topics: '',
  goals_discussed: '',
  blockers: '',
  commitments: '',
  homework: '',
  emotional_themes: '',
  important_quotes: '',
  follow_up_email: '',
  next_session_prep: '',
  private_coach_notes: '',
  shared_client_notes: '',
};

const SessionMemory = () => {
  const router = useRouter();
  const [clients, setClients] = React.useState<Client[]>([]);
  const [sessions, setSessions] = React.useState<Session[]>([]);
  const [clientId, setClientId] = React.useState('');
  const [transcript, setTranscript] = React.useState('');
  const [draft, setDraft] = React.useState<MemoryDraft>(emptyDraft);
  const [audioFile, setAudioFile] = React.useState<File | null>(null);
  const [audioAttachment, setAudioAttachment] =
    React.useState<AudioAttachment | null>(null);
  const [isRecording, setIsRecording] = React.useState(false);
  const [recordingSeconds, setRecordingSeconds] = React.useState(0);
  const [isGenerating, setIsGenerating] = React.useState(false);
  const [isTranscribing, setIsTranscribing] = React.useState(false);
  const [isSaving, setIsSaving] = React.useState(false);
  const [deletingSessionId, setDeletingSessionId] = React.useState('');
  const [notice, setNotice] = React.useState('');
  const [transcriptionNotice, setTranscriptionNotice] = React.useState('');
  const [transcriptionProgress, setTranscriptionProgress] =
    React.useState<TranscriptionProgress | null>(null);
  const [lastSavedSession, setLastSavedSession] =
    React.useState<Session | null>(null);
  const mediaRecorderRef = React.useRef<MediaRecorder | null>(null);
  const mediaStreamRef = React.useRef<MediaStream | null>(null);
  const audioChunksRef = React.useRef<Blob[]>([]);
  const resumedTranscriptionJobRef = React.useRef(false);

  async function loadData() {
    const [clientsResponse, sessionsResponse] = await Promise.all([
      axios.get('/coaching/clients'),
      axios.get('/coaching/session-memory'),
    ]);
    setClients(clientsResponse.data);
    setSessions(sessionsResponse.data);

    const requestedClientId =
      typeof router.query.clientId === 'string' ? router.query.clientId : '';
    const requestedClient = clientsResponse.data.find((client: Client) => {
      return client.id === requestedClientId;
    });

    if (!clientId && requestedClient) {
      setClientId(requestedClient.id);
      return;
    }

    if (!clientId && clientsResponse.data.length > 0) {
      setClientId(clientsResponse.data[0].id);
    }
  }

  React.useEffect(() => {
    if (!router.isReady) {
      return;
    }

    loadData();
  }, [router.isReady, router.query.clientId]);

  React.useEffect(() => {
    if (!isRecording) {
      return;
    }

    const intervalId = window.setInterval(() => {
      setRecordingSeconds((current) => current + 1);
    }, 1000);

    return () => {
      window.clearInterval(intervalId);
    };
  }, [isRecording]);

  React.useEffect(() => {
    return () => {
      stopAudioTracks();
    };
  }, []);

  React.useEffect(() => {
    if (resumedTranscriptionJobRef.current) {
      return;
    }

    const jobId = window.localStorage.getItem(ACTIVE_TRANSCRIPTION_JOB_KEY);

    if (!jobId) {
      return;
    }

    resumedTranscriptionJobRef.current = true;
    setIsTranscribing(true);
    setTranscriptionNotice('Restoring background transcription status.');
    setTranscriptionProgress(null);

    pollTranscriptionJob(jobId)
      .catch((error) => {
        if (axios.isAxiosError(error) && error.response?.status === 404) {
          window.localStorage.removeItem(ACTIVE_TRANSCRIPTION_JOB_KEY);
          setTranscriptionNotice('Previous transcription job is no longer available. Please upload the audio again.');
          setTranscriptionProgress(null);
          return;
        }

        if (error instanceof Error) {
          setTranscriptionNotice(error.message);
          return;
        }

        setTranscriptionNotice(requestErrorMessage(error, 'Audio transcription failed.'));
      })
      .finally(() => {
        setIsTranscribing(false);
      });
  }, []);

  function updateDraft(field: keyof MemoryDraft, value: string) {
    setDraft((current) => {
      return {
        ...current,
        [field]: value,
      };
    });
    setNotice('');
    setLastSavedSession(null);
  }

  async function generateMemory() {
    setIsGenerating(true);

    try {
      const response = await axios.post('/coaching/session-memory/generate', {
        clientId,
        transcript,
      });
      setDraft({
        ...emptyDraft,
        ...response.data,
      });
      setNotice('Draft generated. Review and edit before saving.');
      setLastSavedSession(null);
    } catch (error) {
      setNotice(requestErrorMessage(error, 'Memory generation failed.'));
    } finally {
      setIsGenerating(false);
    }
  }

  function applyTranscriptionResult(result: TranscriptionResult) {
    setTranscript(result.text || '');
    setAudioAttachment({
      audio_url: result.audio_url,
      audio_filename: result.audio_filename,
      audio_mime_type: result.audio_mime_type,
      audio_size: result.audio_size,
    });

    setTranscriptionProgress(null);

    if (result.transcription_chunks && result.transcription_chunks > 1) {
      setTranscriptionNotice(
        'Audio transcribed and saved. Review the transcript before generating memory.',
      );
      setNotice('');
    } else {
      setTranscriptionNotice(
        'Audio transcribed and saved. Review the transcript before generating memory.',
      );
      setNotice('');
    }
  }

  async function pollTranscriptionJob(jobId: string) {
    while (true) {
      await wait(2500);
      const response = await axios.get<TranscriptionJob>(
        `/coaching/session-memory/transcribe/${jobId}`,
      );
      const job = response.data;

      if (job.chunk_index && job.chunks_total) {
        setTranscriptionProgress({
          current: job.chunk_index,
          total: job.chunks_total,
        });
        setTranscriptionNotice('Transcribing audio.');
      } else if (job.status === 'processing') {
        setTranscriptionNotice('Preparing audio transcription.');
      } else if (job.message) {
        setTranscriptionNotice(job.message);
      }

      if (job.status === 'completed') {
        if (!job.result) {
          throw new Error('Transcription job completed without a result.');
        }

        window.localStorage.removeItem(ACTIVE_TRANSCRIPTION_JOB_KEY);
        applyTranscriptionResult(job.result);
        return;
      }

      if (job.status === 'failed') {
        window.localStorage.removeItem(ACTIVE_TRANSCRIPTION_JOB_KEY);
        throw new Error(job.message || 'Audio transcription failed.');
      }
    }
  }

  async function transcribeAudio() {
    if (!audioFile) {
      setTranscriptionNotice('Choose an audio file first.');
      return;
    }

    if (audioFile.size > MAX_AUDIO_FILE_BYTES) {
      setTranscriptionNotice(audioTooLargeMessage());
      return;
    }

    const formData = new FormData();
    formData.append('audio', audioFile);
    formData.append('clientId', clientId);
    setIsTranscribing(true);

    if (audioFile.size > DIRECT_TRANSCRIPTION_FILE_BYTES) {
      setTranscriptionProgress(null);
      setTranscriptionNotice('Large audio detected. Uploading it before background transcription.');
    } else {
      setTranscriptionProgress(null);
      setTranscriptionNotice('Uploading audio before background transcription.');
    }

    try {
      const response = await axios.post(
        '/coaching/session-memory/transcribe',
        formData,
        {
          headers: { 'Content-Type': 'multipart/form-data' },
        },
      );

      if (response.status === 202 && response.data.job_id) {
        window.localStorage.setItem(
          ACTIVE_TRANSCRIPTION_JOB_KEY,
          response.data.job_id,
        );
        setTranscriptionNotice(response.data.message || 'Audio uploaded. Transcription started.');
        await pollTranscriptionJob(response.data.job_id);
        return;
      }

      applyTranscriptionResult(response.data);
    } catch (error) {
      setTranscriptionProgress(null);

      if (error instanceof Error) {
        setTranscriptionNotice(error.message);
      } else {
        setTranscriptionNotice(requestErrorMessage(error, 'Audio transcription failed.'));
      }
    } finally {
      setIsTranscribing(false);
    }
  }

  function stopAudioTracks() {
    if (!mediaStreamRef.current) {
      return;
    }

    mediaStreamRef.current.getTracks().forEach((track) => {
      track.stop();
    });
    mediaStreamRef.current = null;
  }

  function recordedAudioType() {
    if (MediaRecorder.isTypeSupported('audio/webm;codecs=opus')) {
      return 'audio/webm;codecs=opus';
    }

    if (MediaRecorder.isTypeSupported('audio/webm')) {
      return 'audio/webm';
    }

    return '';
  }

  async function startRecording() {
    if (!selectedClient?.recording_consent_granted) {
      setTranscriptionNotice('Recording consent is required for this client.');
      return;
    }
    if (typeof MediaRecorder === 'undefined') {
      setTranscriptionNotice('Audio recording is not supported in this browser.');
      return;
    }

    if (!navigator.mediaDevices?.getUserMedia) {
      setTranscriptionNotice('Audio recording is not supported in this browser.');
      return;
    }

    let stream: MediaStream;

    try {
      stream = await navigator.mediaDevices.getUserMedia({ audio: true });
    } catch (error) {
      setTranscriptionNotice('Microphone access was blocked or failed.');
      return;
    }

    const mimeType = recordedAudioType();
    const options = mimeType ? { mimeType } : undefined;
    const recorder = new MediaRecorder(stream, options);

    audioChunksRef.current = [];
    mediaStreamRef.current = stream;
    mediaRecorderRef.current = recorder;

    recorder.ondataavailable = (event) => {
      if (event.data.size > 0) {
        audioChunksRef.current.push(event.data);
      }
    };

    recorder.onstop = () => {
      const type = recorder.mimeType || 'audio/webm';
      const blob = new Blob(audioChunksRef.current, { type });
      const file = new File([blob], `session-recording-${Date.now()}.webm`, {
        type,
      });

      setAudioFile(file);
      setAudioAttachment(null);
      setTranscriptionNotice('Recording saved. Transcribe it when you are ready.');
      setIsRecording(false);
      stopAudioTracks();
    };

    setRecordingSeconds(0);
    setAudioFile(null);
    setAudioAttachment(null);
    setTranscriptionNotice('');
    setNotice('');
    setIsRecording(true);
    recorder.start();
  }

  function stopRecording() {
    if (!mediaRecorderRef.current) {
      return;
    }

    if (mediaRecorderRef.current.state !== 'inactive') {
      mediaRecorderRef.current.stop();
    }
  }

  function recordingDuration() {
    const minutes = Math.floor(recordingSeconds / 60)
      .toString()
      .padStart(2, '0');
    const seconds = (recordingSeconds % 60).toString().padStart(2, '0');

    return `${minutes}:${seconds}`;
  }

  async function saveMemory() {
    setIsSaving(true);
    try {
      const response = await axios.post('/coaching/session-memory/save', {
        ...draft,
        title:
          draft.title ||
          `Session with ${selectedClient?.name || 'client'} ${new Date().toLocaleDateString()}`,
        clientId,
        transcript_notes: transcript,
        audio_url: audioAttachment?.audio_url,
        audio_filename: audioAttachment?.audio_filename,
        audio_mime_type: audioAttachment?.audio_mime_type,
        audio_size: audioAttachment?.audio_size,
      });

      setSessions((current) => [response.data, ...current]);
      setLastSavedSession(response.data);
      setDraft(emptyDraft);
      setTranscript('');
      setAudioFile(null);
      setAudioAttachment(null);
      setNotice('Session saved as a private coach draft. Open it to approve and share client-visible notes.');
    } finally {
      setIsSaving(false);
    }
  }

  async function deleteSession(session: Session) {
    const confirmed = window.confirm(
      `Delete "${session.title || 'Client session'}"? This cannot be undone.`,
    );

    if (!confirmed) {
      return;
    }

    setDeletingSessionId(session.id);
    try {
      await axios.delete(`/coaching/sessions/${session.id}`);
      setSessions((current) =>
        current.filter((currentSession) => currentSession.id !== session.id),
      );

      if (lastSavedSession?.id === session.id) {
        setLastSavedSession(null);
      }

      setNotice('Session deleted.');
    } finally {
      setDeletingSessionId('');
    }
  }

  async function copyFollowUp() {
    await navigator.clipboard.writeText(draft.follow_up_email || '');
    setNotice('Follow-up copied.');
  }

  const hasDraft = Boolean(
    draft.title ||
      draft.ai_summary ||
      draft.follow_up_email ||
      draft.shared_client_notes,
  );
  const selectedClient = clients.find((client) => client.id === clientId);
  const isStartSessionPage = router.pathname === '/start-session';
  const pageTitle = isStartSessionPage ? 'Start Client Session' : 'Session Memory';

  if (!isStartSessionPage) {
    return (
      <>
        <Head>
          <title>{getPageTitle(pageTitle)}</title>
        </Head>
        <SectionMain>
          <div className='mx-auto max-w-7xl'>
            <div className='mb-4 flex flex-col justify-between gap-4 rounded-none bg-[#19192d] p-7 text-white md:flex-row md:items-end'>
              <div>
                <div className='flex items-center gap-3 text-[#147568]'>
                  <BaseIcon path={mdiFileDocumentEditOutline} size={18} />
                  <span className='text-xs font-semibold uppercase tracking-[0.22em]'>
                    Session Memory
                  </span>
                </div>
                <h1 className='mt-3 max-w-3xl text-xl font-semibold'>
                  Saved client sessions
                </h1>
                <p className='mt-2 max-w-3xl text-sm leading-6 text-[#fffdf9]'>
                  Review transcripts, coach notes, sharing status, and saved
                  session memories.
                </p>
              </div>
              <button
                type='button'
                className='inline-flex items-center justify-center gap-2 rounded-none bg-[#147568] px-4 py-2 text-sm font-semibold text-[#19192d]'
                onClick={() => router.push('/start-session')}
              >
                <BaseIcon path={mdiMicrophoneOutline} size={18} />
                Start new session
              </button>
            </div>

            {notice && (
              <div className='mb-4 rounded-none border border-[#147568]/20 bg-[#fffdf9] px-4 py-3 text-sm font-semibold text-[#147568]'>
                {notice}
              </div>
            )}

            <Panel>
              <div className='border-b border-[#19192d]/10 p-5'>
                <h2 className='text-lg font-semibold text-[#19192d]'>
                  Session archive
                </h2>
              </div>
              <div className='overflow-x-auto'>
                <table className='min-w-full divide-y divide-[#19192d]/10 text-left text-sm'>
                  <thead className='bg-[#fffdf9] text-xs font-semibold uppercase tracking-[0.16em] text-[#5f6675]'>
                    <tr>
                      <th className='px-5 py-3'>Session</th>
                      <th className='px-5 py-3'>Client</th>
                      <th className='px-5 py-3'>Date</th>
                      <th className='px-5 py-3'>Audio</th>
                      <th className='px-5 py-3'>Status</th>
                      <th className='px-5 py-3 text-right'>Actions</th>
                    </tr>
                  </thead>
                  <tbody className='divide-y divide-[#19192d]/10'>
                    {sessions.map((session) => (
                      <React.Fragment key={session.id}>
                        <tr className='align-top'>
                          <td className='px-5 py-4'>
                            <p className='font-semibold text-[#19192d]'>
                              {session.title || 'Client session'}
                            </p>
                            <p className='mt-1 max-w-lg truncate text-sm text-[#5f6675]'>
                              {session.ai_summary || 'No coach summary yet.'}
                            </p>
                          </td>
                          <td className='px-5 py-4 text-[#19192d]'>
                            {session.client?.name || 'No client'}
                          </td>
                          <td className='px-5 py-4 text-[#5f6675]'>
                            {displayDateTime(session.session_at)}
                          </td>
                          <td className='px-5 py-4 text-[#5f6675]'>
                            {session.audio_url ? 'Saved' : 'None'}
                          </td>
                          <td className='px-5 py-4'>
                            <StatusPill status={session.status} />
                          </td>
                          <td className='px-5 py-4'>
                            <div className='flex flex-wrap justify-end gap-2'>
                              <button
                                type='button'
                                className='inline-flex items-center gap-2 rounded-none border border-[#19192d]/10 bg-white px-3 py-2 text-sm font-semibold text-[#19192d]'
                                onClick={() =>
                                  router.push(
                                    `/session-memory/view?sessionId=${session.id}`,
                                  )
                                }
                              >
                                <BaseIcon
                                  path={mdiFileDocumentEditOutline}
                                  size={18}
                                />
                                Open
                              </button>
                              <button
                                type='button'
                                className='inline-flex items-center gap-2 rounded-none border border-[#19192d]/10 bg-white px-3 py-2 text-sm font-semibold text-[#19192d] disabled:opacity-50'
                                disabled={deletingSessionId === session.id}
                                onClick={() => deleteSession(session)}
                              >
                                <BaseIcon path={mdiTrashCanOutline} size={18} />
                                {deletingSessionId === session.id
                                  ? 'Deleting...'
                                  : 'Delete'}
                              </button>
                            </div>
                          </td>
                        </tr>
                      </React.Fragment>
                    ))}
                    {sessions.length === 0 && (
                      <tr>
                        <td
                          colSpan={6}
                          className='px-5 py-8 text-center text-sm text-[#5f6675]'
                        >
                          No saved sessions yet.
                        </td>
                      </tr>
                    )}
                  </tbody>
                </table>
              </div>
            </Panel>
          </div>
        </SectionMain>
      </>
    );
  }

  return (
    <>
      <Head>
        <title>{getPageTitle(pageTitle)}</title>
      </Head>
      <SectionMain>
        <div className='mx-auto max-w-7xl'>
          <div className='mb-4 rounded-none bg-[#19192d] p-7 text-white'>
            <div className='flex items-center gap-3 text-[#147568]'>
              <BaseIcon path={mdiFileDocumentEditOutline} size={18} />
              <span className='text-xs font-semibold uppercase tracking-[0.22em]'>
                {isStartSessionPage ? 'Start session' : 'Session Memory'}
              </span>
            </div>
            <h1 className='mt-3 max-w-3xl text-xl font-semibold'>
              {isStartSessionPage
                ? 'Record or upload a client session, then turn it into memory.'
                : 'Turn rough notes into follow-up, commitments, and next-session prep.'}
            </h1>
            <p className='mt-2 max-w-3xl text-sm leading-6 text-[#fffdf9]'>
              {isStartSessionPage
                ? 'Choose the client, capture audio or upload a file, transcribe it, and generate the coach review.'
                : 'Generate a structured draft, edit it as the coach, save it as a private draft, or share approved notes with the client portal.'}
            </p>
          </div>

          {notice && (
            <div className='mb-4 rounded-none border border-[#147568]/20 bg-[#fffdf9] px-4 py-3 text-sm font-semibold text-[#147568]'>
              {notice}
            </div>
          )}

          <div className='grid gap-6 xl:grid-cols-[0.8fr_1.2fr]'>
            <Panel className='p-4'>
              <p className='text-xs font-semibold uppercase tracking-[0.22em] text-[#147568]'>
                Raw session input
              </p>
              <h2 className='mt-2 text-lg font-semibold text-[#19192d]'>
                {isStartSessionPage ? 'Capture this session' : 'Extract a session'}
              </h2>

              <label className='mb-2 mt-6 block text-sm font-semibold text-[#5f6675]'>
                Client
              </label>
              <select
                value={clientId}
                onChange={(event) => setClientId(event.target.value)}
                className='w-full rounded-none border border-[#19192d]/10 bg-white px-4 py-3 text-[#19192d] outline-none focus:border-[#147568] focus:ring-2 focus:ring-[#147568]/15'
              >
                {clients.map((client) => (
                  <option key={client.id} value={client.id}>
                    {client.name}
                  </option>
                ))}
              </select>

              <div className='mt-5 rounded-none border border-[#19192d]/10 bg-[#fffdf9] p-3'>
                <div className='flex items-center gap-2 text-sm font-semibold text-[#19192d]'>
                  <BaseIcon path={mdiMicrophoneOutline} size={18} />
                  Audio transcription
                </div>
                <div className='mt-4 border border-[#19192d]/10 bg-white p-4'>
                  <div className='flex flex-col gap-4 md:flex-row md:items-center md:justify-between'>
                    <div>
                      <p className='text-sm font-semibold text-[#19192d]'>
                        Record audio
                      </p>
                      <p className='mt-1 text-sm text-[#5f6675]'>
                        {isRecording
                          ? `Recording ${recordingDuration()}`
                          : 'Use your microphone and transcribe the recording below.'}
                      </p>
                    </div>
                    {isRecording ? (
                      <button
                        type='button'
                        className='inline-flex items-center justify-center gap-2 rounded-none bg-[#19192d] px-4 py-2 text-sm font-semibold text-white'
                        onClick={stopRecording}
                      >
                        <BaseIcon path={mdiStopCircleOutline} size={18} />
                        Stop recording
                      </button>
                    ) : (
                      <button
                        type='button'
                        className='inline-flex items-center justify-center gap-2 rounded-none bg-[#147568] px-4 py-2 text-sm font-semibold text-white disabled:opacity-50'
                        disabled={isTranscribing}
                        onClick={startRecording}
                      >
                        <BaseIcon path={mdiMicrophoneOutline} size={18} />
                        Start recording
                      </button>
                    )}
                  </div>
                </div>
                <label className='mt-3 flex cursor-pointer items-center justify-between gap-3 rounded-none border border-dashed border-[#19192d]/15 bg-white px-4 py-4 text-sm text-[#5f6675]'>
                  <span className='truncate'>
                    {audioFile ? audioFile.name : 'Choose an audio file'}
                  </span>
                  <span className='inline-flex items-center gap-2 rounded-none bg-[#fffdf9] px-3 py-1 text-xs font-semibold text-[#147568]'>
                    <BaseIcon path={mdiCloudUploadOutline} size={16} />
                    Upload
                  </span>
                  <input
                    type='file'
                    accept='audio/*'
                    className='hidden'
                    onChange={(event) => {
                      const file = event.target.files?.[0] || null;
                      setAudioAttachment(null);

                      if (file && file.size > MAX_AUDIO_FILE_BYTES) {
                        setAudioFile(null);
                        setTranscriptionNotice(audioTooLargeMessage());
                        event.target.value = '';
                        return;
                      }

                      setAudioFile(file);
                      setTranscriptionNotice('');
                      setTranscriptionProgress(null);
                      setNotice('');
                    }}
                  />
                </label>
                <button
                  type='button'
                  className='mt-3 inline-flex items-center gap-2 rounded-none bg-[#147568] px-4 py-2 text-sm font-semibold text-white disabled:opacity-50'
                  disabled={isTranscribing || !audioFile}
                  onClick={transcribeAudio}
                >
                  <BaseIcon path={mdiMicrophoneOutline} size={18} />
                  {isTranscribing ? 'Transcribing...' : 'Transcribe audio'}
                </button>
                {(transcriptionNotice || transcriptionProgress) && (
                  <div className='mt-3 rounded-none border border-[#147568]/20 bg-[#fffdf9] px-4 py-3 text-sm font-semibold text-[#147568]'>
                    {transcriptionProgress && (
                      <div className='mb-2 h-2 w-full overflow-hidden rounded-none bg-[#147568]/15'>
                        <div
                          className='h-full rounded-none bg-[#147568] transition-[width] duration-300'
                          style={{
                            width: `${Math.min(
                              100,
                              Math.max(
                                4,
                                Math.round(
                                  (transcriptionProgress.current /
                                    transcriptionProgress.total) *
                                    100,
                                ),
                              ),
                            )}%`,
                          }}
                        />
                      </div>
                    )}
                    {transcriptionNotice}
                  </div>
                )}
                {audioAttachment?.audio_url && (
                  <div className='mt-3 rounded-none border border-[#19192d]/10 bg-white p-4'>
                    <p className='text-sm font-semibold text-[#19192d]'>
                      Audio saved for this session
                    </p>
                    <audio
                      className='mt-3 w-full'
                      controls
                      src={audioAttachment.audio_url}
                    />
                    <p className='mt-2 text-xs text-[#5f6675]'>
                      {audioAttachment.audio_filename || 'Session audio'}
                    </p>
                  </div>
                )}
              </div>

              <label className='mb-2 mt-5 block text-sm font-semibold text-[#5f6675]'>
                Transcript or raw notes
              </label>
              <textarea
                value={transcript}
                onChange={(event) => setTranscript(event.target.value)}
                className='min-h-[220px] w-full rounded-none border border-[#19192d]/10 bg-[#fffdf9] px-4 py-3 leading-6 text-[#19192d] outline-none focus:border-[#147568] focus:ring-2 focus:ring-[#147568]/15'
                placeholder='Paste session transcript, coach notes, commitments, blockers, or a rough debrief...'
              />
              <div className='mt-5 flex flex-wrap gap-3'>
                <button
                  type='button'
                  className='inline-flex items-center justify-center gap-2 rounded-none bg-[#147568] px-4 py-2 text-sm font-semibold text-white disabled:opacity-50'
                  disabled={isGenerating || !clientId || !transcript.trim()}
                  onClick={generateMemory}
                >
                  <BaseIcon path={mdiFileDocumentEditOutline} size={18} />
                  {isGenerating
                    ? 'Generating review...'
                    : 'Generate coach review'}
                </button>
                <button
                  type='button'
                  className='inline-flex items-center justify-center gap-2 rounded-none border border-[#19192d]/10 bg-white px-4 py-2 text-sm font-semibold text-[#19192d] disabled:opacity-50'
                  disabled={isSaving || !clientId || !transcript.trim()}
                  onClick={saveMemory}
                >
                  <BaseIcon path={mdiCheckCircleOutline} size={18} />
                  {isSaving ? 'Saving session...' : 'Save session'}
                </button>
              </div>
            </Panel>

            <div className='space-y-4'>
              {transcript.trim() && (
                <Panel className='p-4'>
                  <p className='text-xs font-semibold uppercase tracking-[0.22em] text-[#147568]'>
                    Session transcript
                  </p>
                  <h2 className='mt-2 text-lg font-semibold text-[#19192d]'>
                    Speaker view
                  </h2>
                  <div className='mt-4 max-h-[420px] overflow-y-auto'>
                    <TranscriptConversation value={transcript} />
                  </div>
                </Panel>
              )}

              <Panel className='p-4'>
                <div className='flex items-start justify-between gap-6'>
                  <div>
                    <p className='text-xs font-semibold uppercase tracking-[0.22em] text-[#147568]'>
                      Coach review
                    </p>
                    <h2 className='mt-2 text-lg font-semibold text-[#19192d]'>
                      Edit the final memory
                    </h2>
                  </div>
                  {hasDraft && (
                    <span className='rounded-none bg-[#fffdf9] px-3 py-1 text-xs font-semibold text-[#147568]'>
                      Draft not shared yet
                    </span>
                  )}
                  {!hasDraft && lastSavedSession && (
                    <StatusPill status={lastSavedSession.status} />
                  )}
                </div>

                {hasDraft ? (
                  <div className='mt-4 grid gap-6'>
                    <label className='block'>
                      <span className='text-xs font-semibold uppercase tracking-[0.18em] text-[#147568]'>
                        Title
                      </span>
                      <input
                        value={draft.title || ''}
                        onChange={(event) =>
                          updateDraft('title', event.target.value)
                        }
                        className='mt-2 w-full rounded-none border border-[#19192d]/10 bg-[#fffdf9] px-4 py-3 text-sm text-[#19192d] outline-none focus:border-[#147568] focus:ring-2 focus:ring-[#147568]/15'
                      />
                    </label>

                    <TextField
                      label='Summary'
                      value={draft.ai_summary || ''}
                      onChange={(value) => updateDraft('ai_summary', value)}
                      rows={4}
                    />
                    <TextField
                      label='Commitments'
                      value={draft.commitments || ''}
                      onChange={(value) => updateDraft('commitments', value)}
                    />
                    <TextField
                      label='Homework'
                      value={draft.homework || ''}
                      onChange={(value) => updateDraft('homework', value)}
                    />
                    <TextField
                      label='Shared client notes'
                      value={draft.shared_client_notes || ''}
                      onChange={(value) =>
                        updateDraft('shared_client_notes', value)
                      }
                      rows={4}
                    />
                    <TextField
                      label='Follow-up email'
                      value={draft.follow_up_email || ''}
                      onChange={(value) =>
                        updateDraft('follow_up_email', value)
                      }
                      rows={4}
                    />
                    <TextField
                      label='Next-session prep'
                      value={draft.next_session_prep || ''}
                      onChange={(value) =>
                        updateDraft('next_session_prep', value)
                      }
                    />
                    <TextField
                      label='Private coach notes'
                      value={draft.private_coach_notes || ''}
                      onChange={(value) =>
                        updateDraft('private_coach_notes', value)
                      }
                    />

                    <div className='flex flex-wrap gap-3'>
                      <button
                        type='button'
                        className='inline-flex items-center gap-2 rounded-none bg-[#19192d] px-4 py-2 text-sm font-semibold text-white disabled:opacity-50'
                        disabled={isSaving}
                        onClick={saveMemory}
                      >
                        <BaseIcon path={mdiCheckCircleOutline} size={18} />
                        Save session draft
                      </button>
                      <button
                        type='button'
                        className='inline-flex items-center gap-2 rounded-none border border-[#19192d]/10 bg-white px-4 py-2 text-sm font-semibold text-[#19192d]'
                        onClick={copyFollowUp}
                      >
                        <BaseIcon path={mdiContentCopy} size={18} />
                        Copy follow-up
                      </button>
                    </div>
                  </div>
                ) : lastSavedSession ? (
                  <div className='mt-4 rounded-none border border-[#147568]/20 bg-[#fffdf9] p-6'>
                    <BaseIcon
                      path={
                        lastSavedSession.status === 'shared'
                          ? mdiSendOutline
                          : mdiCheckCircleOutline
                      }
                      size={22}
                      className='text-[#147568]'
                    />
                    <p className='mt-4 font-semibold text-[#19192d]'>
                      {lastSavedSession.status === 'shared'
                        ? 'Shared with client'
                        : 'Saved as coach draft'}
                    </p>
                    <p className='mt-2 leading-6 text-[#5f6675]'>
                      {lastSavedSession.title} was saved for{' '}
                      {lastSavedSession.client?.name ||
                        selectedClient?.name ||
                        'the selected client'}
                      .
                    </p>
                    <p className='mt-3 text-sm font-semibold text-[#147568]'>
                      You can find it in Recent memories below.
                    </p>
                  </div>
                ) : (
                  <div className='mt-4 rounded-none border border-dashed border-[#19192d]/10 bg-[#fffdf9] p-6'>
                    <BaseIcon
                      path={mdiLightbulbOnOutline}
                      size={22}
                      className='text-[#147568]'
                    />
                    <p className='mt-4 leading-6 text-[#5f6675]'>
                      Generate a coach review from the transcript. The editable
                      draft will appear here before anything is saved or shared.
                    </p>
                  </div>
                )}
              </Panel>

            </div>
          </div>
        </div>
      </SectionMain>
    </>
  );
};

SessionMemory.getLayout = function getLayout(page: ReactElement) {
  return <LayoutAuthenticated>{page}</LayoutAuthenticated>;
};

export default SessionMemory;
