const { form, button, div, h2, p, section, input, label, br, a, span, table, thead, tbody, tr, th, td, textarea, select, option, ul, li, img } = require('../server/node_modules/hyperaxe');
const moment = require('../server/node_modules/moment');
const { template, i18n, userLink, renderStateChip } = require('./main_views');

const CourtsE2EChip = () => renderStateChip('encrypted', '🔒', i18n.encryptedChipLabel || 'E2E');

const fmt = (d) => moment(d).format('YYYY-MM-DD HH:mm:ss');

const applyEl = (fn, attrs, kids) => fn.apply(null, [attrs || {}].concat(kids || []));

const methodKey = (m) => String(m || '').toUpperCase();

const methodLabel = (m) => {
  const key = `courtsMethod${methodKey(m)}`;
  const raw = i18n[key] || '';
  return String(raw).toUpperCase();
};

const showVoteMetrics = (m) => {
  const k = methodKey(m);
  return k === 'POPULAR' || k === 'KARMATOCRACY';
};

const CASE_TITLE_PRESETS = [
  'Minor conflict',
  'Moderate conflict',
  'Severe conflict',
  'Harassment or abuse',
  'Content moderation',
  'Ban or restriction',
  'Governance dispute'
];

const FILTERS = [
  { value: 'cases', key: 'courtsFilterCases' },
  { value: 'mycases', key: 'courtsFilterMyCases' },
  { value: 'actions', key: 'courtsFilterActions' },
  { value: 'judges', key: 'courtsFilterJudges' },
  { value: 'history', key: 'courtsFilterHistory' },
  { value: 'rules', key: 'courtsFilterRules' },
  { value: 'open', key: 'courtsFilterOpenCase' }
];

const Tabs = (active) =>
  div(
    { class: 'filters' },
    form(
      { method: 'GET', action: '/courts' },
      FILTERS.map((f) => {
        const isOpen = f.value === 'open';
        const cls =
          isOpen
            ? 'create-button'
            : active === f.value
            ? 'filter-btn active'
            : 'filter-btn';
        return button(
          {
            type: 'submit',
            name: 'filter',
            value: f.value,
            class: cls
          },
          i18n[f.key]
        );
      })
    )
  );

const CaseForm = (prefill = {}) =>
  div(
    { class: 'div-center' },
    h2(i18n.courtsCaseFormTitle),
    form(
      {
        method: 'POST',
        action: '/courts/cases/create'
      },
      label(i18n.courtsCaseTitle),
      br(),
      input({
        type: 'text',
        name: 'titleSuffix',
        required: true,
        placeholder: 'Subject or short description',
        value: prefill.titleSuffix || ''
      }),
      br(),
      label('Case type'),
      br(),
      select(
        { name: 'titlePreset', required: true },
        CASE_TITLE_PRESETS.map((t) => option({ value: t, ...(prefill.titlePreset === t ? { selected: true } : {}) }, t))
      ),
      br(),
      br(),
      label(i18n.courtsCaseRespondent),
      br(),
      input({
        type: 'text',
        name: 'respondentId',
        placeholder: i18n.courtsCaseRespondentPh,
        required: true,
        pattern: '^@[A-Za-z0-9+/]+=*\\.ed25519$',
        title: i18n.courtsRespondentInvalid || 'Must be a valid SSB ID (@...ed25519)',
        value: prefill.respondentId || ''
      }),
      br(),
      label(i18n.courtsCaseMethod),
      br(),
      select(
        { name: 'method', required: true },
        ['JUDGE', 'DICTATOR', 'POPULAR', 'MEDIATION', 'KARMATOCRACY'].map((m) =>
          option({ value: m, ...(prefill.method === m ? { selected: true } : {}) }, i18n[`courtsMethod${m}`])
        )
      ),
      br(),
      br(),
      button({ type: 'submit', class: 'create-button' }, i18n.courtsCaseSubmit)
    )
  );

const NominateJudgeForm = () =>
  div(
    { class: 'div-center' },
    h2(i18n.courtsNominateJudge),
    form(
      { method: 'POST', action: '/courts/judges/nominate' },
      label(i18n.courtsJudgeId),
      br(),
      input({
        type: 'text',
        name: 'judgeId',
        placeholder: i18n.courtsJudgeIdPh,
        required: true
      }),
      br(),
      br(),
      button({ type: 'submit', class: 'create-button' }, i18n.courtsNominateBtn)
    )
  );

const EvidenceForm = (caseId) =>
  div(
    { class: 'div-center' },
    h2(i18n.courtsAddEvidence),
    form(
      {
        method: 'POST',
        action: `/courts/cases/${encodeURIComponent(caseId)}/evidence/add`,
        enctype: 'multipart/form-data'
      },
      label(i18n.courtsEvidenceText),
      br(),
      textarea({ name: 'text', rows: 3, maxlength: 1000 }),
      br(),
      br(),
      label(i18n.courtsEvidenceLink),
      br(),
      input({
        type: 'url',
        name: 'link',
        placeholder: i18n.courtsEvidenceLinkPh
      }),
      br(),
      br(),
      label(i18n.uploadMedia || 'Upload media (max-size: 50MB)'),
      br(),
      input({ type: 'file', name: 'image' }),
      br(),
      br(),
      button({ type: 'submit', class: 'create-button' }, i18n.courtsEvidenceSubmit)
    )
  );

const AnswerForm = (caseId) =>
  div(
    { class: 'div-center' },
    h2(i18n.courtsAnswerTitle),
    form(
      {
        method: 'POST',
        action: `/courts/cases/${encodeURIComponent(caseId)}/answer`
      },
      label(i18n.courtsAnswerText),
      br(),
      textarea({ name: 'answer', rows: 4, maxlength: 2000 }),
      br(),
      br(),
      select(
        { name: 'stance' },
        ['DENY', 'ADMIT', 'PARTIAL'].map((s) =>
          option({ value: s }, i18n[`courtsStance${s}`])
        )
      ),
      br(),
      br(),
      button({ type: 'submit', class: 'create-button' }, i18n.courtsAnswerSubmit)
    )
  );

const VerdictForm = (caseId) =>
  div(
    { class: 'div-center' },
    h2(i18n.courtsVerdictTitle),
    form(
      {
        method: 'POST',
        action: `/courts/cases/${encodeURIComponent(caseId)}/decide`
      },
      label(i18n.courtsVerdictResult),
      br(),
      input({ type: 'text', name: 'outcome', required: true }),
      br(),
      br(),
      label(i18n.courtsVerdictOrders),
      br(),
      textarea({
        name: 'orders',
        rows: 4,
        maxlength: 2000,
        placeholder: i18n.courtsVerdictOrdersPh
      }),
      br(),
      br(),
      button({ type: 'submit', class: 'create-button' }, i18n.courtsIssueVerdict)
    )
  );

const SettlementForm = (caseId) =>
  div(
    { class: 'div-center' },
    h2(i18n.courtsMediationPropose),
    form(
      {
        method: 'POST',
        action: `/courts/cases/${encodeURIComponent(caseId)}/settlements/propose`
      },
      label(i18n.courtsSettlementText),
      br(),
      textarea({ name: 'terms', rows: 3, maxlength: 2000 }),
      br(),
      br(),
      button(
        { type: 'submit', class: 'create-button' },
        i18n.courtsSettlementProposeBtn
      )
    )
  );

const RespondentMediatorsForm = (c) => {
  if (
    !c.isRespondent ||
    c.status === 'SOLVED' ||
    c.status === 'UNSOLVED' ||
    c.status === 'DISCARDED'
  )
    return null;
  return div(
    { class: 'div-center' },
    h2(i18n.courtsCaseMediatorsRespondentTitle),
    form(
      {
        method: 'POST',
        action: `/courts/cases/${encodeURIComponent(c.id)}/mediators/respondent`
      },
      label(i18n.courtsCaseMediatorsRespondent),
      br(),
      input({
        type: 'text',
        name: 'mediators',
        placeholder: i18n.courtsCaseMediatorsPh
      }),
      br(),
      br(),
      button({ type: 'submit', class: 'create-button' }, i18n.courtsMediatorsSubmit)
    )
  );
};

const JudgeAssignForm = (caseId) =>
  div(
    { class: 'div-center' },
    h2(i18n.courtsAssignJudgeTitle),
    form(
      {
        method: 'POST',
        action: `/courts/cases/${encodeURIComponent(caseId)}/judge`
      },
      label(i18n.courtsJudgeId),
      br(),
      input({
        type: 'text',
        name: 'judgeId',
        placeholder: i18n.courtsJudgeIdPh,
        required: true
      }),
      br(),
      br(),
      button(
        { type: 'submit', class: 'create-button' },
        i18n.courtsAssignJudgeBtn
      )
    )
  );

const SupportCaseForm = (caseId) =>
  form(
    {
      method: 'POST',
      action: `/courts/cases/${encodeURIComponent(caseId)}/support`
    },
    button({ type: 'submit', class: 'vote-btn' }, i18n.courtsSupportCase)
  );

const OpenVoteForm = (caseId) =>
  form(
    { method: 'POST', action: `/courts/cases/${encodeURIComponent(caseId)}/openVote` },
    button({ type: 'submit', class: 'create-button' }, i18n.courtsOpenVote)
  );

const AcceptSettlementForm = (caseId) =>
  form(
    { method: 'POST', action: `/courts/cases/${encodeURIComponent(caseId)}/settlements/accept` },
    button({ type: 'submit', class: 'create-button' }, i18n.courtsSettlementAcceptBtn)
  );

const VerdictVoteForm = (caseId) =>
  div(
    { class: 'div-center' },
    h2(i18n.courtsVerdictVoteTitle),
    form(
      {
        method: 'POST',
        action: `/courts/cases/${encodeURIComponent(caseId)}/verdict/vote`
      },
      label(i18n.courtsVerdictVoteLabel),
      br(),
      select(
        { name: 'decision' },
        option({ value: 'ACCEPT' }, i18n.courtsVerdictVoteAccept),
        option({ value: 'REJECT' }, i18n.courtsVerdictVoteReject)
      ),
      br(),
      br(),
      button(
        { type: 'submit', class: 'create-button' },
        i18n.courtsVerdictVoteSubmit
      )
    )
  );

const shortId = (id) => {
  const s = String(id || '');
  if (!s) return '';
  if (s.length <= 16) return s;
  return `${s.slice(0, 6)}…${s.slice(-4)}`;
};

const UserLinkCompact = (id) => id ? userLink(id) : span('');
const UserLinkFull = (id) => id ? userLink(id) : span('');

const renderRichTextNodes = (raw) => {
  const text = String(raw || '');
  if (!text) return [];
  const nodes = [];
  let remaining = text;
  const imgRegex = /!\[[^\]]*]\(([^)]+)\)/;
  const linkRegex = /\[([^\]]+)]\((https?:\/\/[^)]+)\)/;
  while (remaining.length) {
    const imgMatch = imgRegex.exec(remaining);
    const linkMatch = linkRegex.exec(remaining);
    let next = null;
    let type = null;
    if (imgMatch && (!linkMatch || imgMatch.index < linkMatch.index)) {
      next = imgMatch;
      type = 'img';
    } else if (linkMatch) {
      next = linkMatch;
      type = 'link';
    }
    if (!next) {
      if (remaining.trim()) nodes.push(p(remaining));
      break;
    }
    const idx = next.index;
    if (idx > 0) {
      const before = remaining.slice(0, idx);
      if (before.trim()) nodes.push(p(before));
    }
    if (type === 'img') {
      const ref = next[1];
      nodes.push(
        img({
          class: 'evidence-image',
          src: `/blob/${encodeURIComponent(ref)}`,
          alt: 'evidence'
        })
      );
    } else {
      const labelText = next[1];
      const url = next[2];
      nodes.push(
        a(
          {
            class: 'evidence-link',
            href: url,
            target: '_blank',
            rel: 'noopener noreferrer'
          },
          labelText
        )
      );
    }
    remaining = remaining.slice(idx + next[0].length);
  }
  return nodes;
};

const RichTextBlock = (raw) => {
  const nodes = renderRichTextNodes(raw);
  if (!nodes.length) return null;
  return nodes;
};

const CaseCard = (c) => {
  const mid = methodKey(c.method);
  const yes = Number(c.yes || 0);
  const total = Number(c.total || 0);
  const needed = Number(c.needed || 0);
  const showMetricsFlag = showVoteMetrics(mid) && (total > 0 || needed > 0);
  const accLink = UserLinkCompact(c.accuser);
  const resLink = UserLinkCompact(c.respondent);
  const mediatorsAccuser = Array.isArray(c.mediatorsAccuser)
    ? c.mediatorsAccuser
    : [];
  const mediatorsRespondent = Array.isArray(c.mediatorsRespondent)
    ? c.mediatorsRespondent
    : [];
  const canShowDetails = c.mine || c.publicDetails;
  const mediatorLinksAccuser = mediatorsAccuser.map((mId, idx) =>
    span(
      { class: 'mediator' },
      userLink(mId),
      idx < mediatorsAccuser.length - 1 ? span(', ') : null
    )
  );
  const mediatorLinksRespondent = mediatorsRespondent.map((mId, idx) =>
    span(
      { class: 'mediator' },
      userLink(mId),
      idx < mediatorsRespondent.length - 1 ? span(', ') : null
    )
  );
  const showPublicPrefForm =
    (c.status === 'DECIDED' ||
      c.status === 'CLOSED' ||
      c.status === 'SOLVED' ||
      c.status === 'UNSOLVED' ||
      c.status === 'DISCARDED') &&
    (c.isAccuser || c.isRespondent);
  const publicPreferenceForm = showPublicPrefForm
    ? form(
        {
          method: 'POST',
          action: `/courts/cases/${encodeURIComponent(c.id)}/public`
        },
        label(i18n.courtsPublicPrefLabel),
        br(),
        select(
          { name: 'preference' },
          option(
            { value: 'YES', ...(c.myPublicPreference === true ? { selected: true } : {})},
            i18n.courtsPublicPrefYes
          ),
          option(
            { value: 'NO', ...(c.myPublicPreference === false ? { selected: true } : {})},
            i18n.courtsPublicPrefNo
          )
        ),
        br(),
        br(),
        button(
          { type: 'submit', class: 'create-button' },
          i18n.courtsPublicPrefSubmit
        )
      )
    : null;
  const respondentMediatorsForm = RespondentMediatorsForm(c);
  const canAddEvidence =
    c.isAccuser || c.isRespondent || c.isMediator || c.isJudge || c.isDictator;
  const canAnswer = c.isRespondent;
  const canIssueVerdict =
    ((methodKey(c.method) === 'JUDGE' && c.isJudge) ||
      (methodKey(c.method) === 'MEDIATION' && c.isMediator) ||
      (methodKey(c.method) === 'DICTATOR' && c.isDictator)) &&
    (c.status === 'OPEN' || c.status === 'IN_PROGRESS') &&
    !c.hasVerdict;
  const canProposeSettlement =
    (c.isAccuser || c.isRespondent || c.isMediator) &&
    methodKey(c.method) === 'MEDIATION' &&
    c.status === 'OPEN';
  const canOpenVote =
    (c.isAccuser || c.isRespondent) &&
    (methodKey(c.method) === 'POPULAR' || methodKey(c.method) === 'KARMATOCRACY') &&
    (c.status === 'OPEN' || c.status === 'IN_PROGRESS') &&
    !c.voteId;
  const canAcceptSettlement =
    (c.isAccuser || c.isRespondent) &&
    methodKey(c.method) === 'MEDIATION' &&
    (c.status === 'OPEN' || c.status === 'IN_PROGRESS') &&
    !!c.hasSettlement;
  const isNormalUser =
    !c.isAccuser &&
    !c.isRespondent &&
    !c.isMediator &&
    !c.isJudge &&
    !c.isDictator;
  const canSupport =
    isNormalUser &&
    (c.status === 'IN_PROGRESS' || c.status === 'OPEN');
  const canAssignJudge =
    methodKey(c.method) === 'JUDGE' &&
    !c.judgeId &&
    (c.isAccuser || c.isRespondent);
  return div(
    { class: 'card' },
    div(
      { class: 'card-header' },
      div(
        { class: 'card-header__meta' },
        h2(c.title || ''),
        div({ class: 'card-chips-row' }, CourtsE2EChip()),
        div(
          { class: 'card-field' },
          span({ class: 'card-label' }, i18n.courtsCaseMethod + ': '),
          span({ class: 'card-value' }, methodLabel(c.method))
        ),
        div(
          { class: 'card-field' },
          span({ class: 'card-label' }, i18n.courtsThStatus + ': '),
          span({ class: 'card-value' }, String(c.status || ''))
        ),
        c.answerBy
          ? div(
              { class: 'card-field' },
              span({ class: 'card-label' }, i18n.courtsThAnswerBy + ': '),
              span({ class: 'card-value' }, fmt(c.answerBy))
            )
          : null,
        c.evidenceBy
          ? div(
              { class: 'card-field' },
              span({ class: 'card-label' }, i18n.courtsThEvidenceBy + ': '),
              span({ class: 'card-value' }, fmt(c.evidenceBy))
            )
          : null
      )
    ),
    div(
      { class: 'table-wrap mt-2' },
      applyEl(table, { class: 'table table--centered' }, [
        thead(tr(th(i18n.courtsAccuser), th(i18n.courtsRespondent))),
        tbody(tr(td(accLink), td(resLink)))
      ])
    ),
    mediatorsAccuser.length
      ? div(
          { class: 'card-field' },
          span(
            { class: 'card-label' },
            i18n.courtsMediatorsAccuserLabel + ': '
          ),
          span({ class: 'card-value' }, ...mediatorLinksAccuser)
        )
      : null,
    mediatorsRespondent.length
      ? div(
          { class: 'card-field' },
          span(
            { class: 'card-label' },
            i18n.courtsMediatorsRespondentLabel + ': '
          ),
          span({ class: 'card-value' }, ...mediatorLinksRespondent)
        )
      : null,
    c.supportCount
      ? div(
          { class: 'card-field' },
          span({ class: 'card-label' }, i18n.courtsSupportCount + ': '),
          span({ class: 'card-value' }, String(c.supportCount))
        )
      : null,
    canShowDetails ? RichTextBlock(c.description || '') : null,
    showMetricsFlag
      ? div(
          { class: 'card-field' },
          span({ class: 'card-label' }, i18n.courtsVotesNeeded + ': '),
          span({ class: 'card-value' }, String(needed))
        )
      : null,
    showMetricsFlag
      ? div(
          { class: 'card-field' },
          span({ class: 'card-label' }, i18n.courtsVotesSlashTotal + ': '),
          span({ class: 'card-value' }, `${yes}/${total}`)
        )
      : null,
    c.voteId
      ? form(
          { method: 'GET', action: `/votes/${encodeURIComponent(c.voteId)}` },
          button({ type: 'submit', class: 'vote-btn' }, i18n.courtsOpenVote)
        )
      : null,
    canSupport ? SupportCaseForm(c.id || '') : null,
    publicPreferenceForm,
    respondentMediatorsForm,
    canAssignJudge ? JudgeAssignForm(c.id || '') : null,
    canAddEvidence ? EvidenceForm(c.id || '') : null,
    canAnswer ? AnswerForm(c.id || '') : null,
    canIssueVerdict ? VerdictForm(c.id || '') : null,
    canProposeSettlement ? SettlementForm(c.id || '') : null,
    canOpenVote ? OpenVoteForm(c.id || '') : null,
    canAcceptSettlement ? AcceptSettlementForm(c.id || '') : null
  );
};

const MyCaseCard = (c) => {
  const mid = methodKey(c.method);
  const yes = Number(c.yes || 0);
  const total = Number(c.total || 0);
  const needed = Number(c.needed || 0);
  const showMetricsFlag = showVoteMetrics(mid) && (total > 0 || needed > 0);

  const accLinkFull = UserLinkFull(c.accuser);
  const respondentId = c.respondentId || c.respondent;
  const resLinkFull = UserLinkFull(respondentId);

  const mediatorsAccuser = Array.isArray(c.mediatorsAccuser)
    ? c.mediatorsAccuser
    : [];
  const mediatorsRespondent = Array.isArray(c.mediatorsRespondent)
    ? c.mediatorsRespondent
    : [];

  const mediatorLinksAccuser = mediatorsAccuser.map((mId, idx) =>
    span(
      {},
      userLink(mId),
      idx < mediatorsAccuser.length - 1 ? span(', ') : null
    )
  );

  const mediatorLinksRespondent = mediatorsRespondent.map((mId, idx) =>
    span(
      {},
      userLink(mId),
      idx < mediatorsRespondent.length - 1 ? span(', ') : null
    )
  );

  const judgeLinkFull = c.judgeId ? UserLinkFull(c.judgeId) : span('');
  const showMediatorsTable =
    !!c.method &&
    (mediatorsAccuser.length > 0 ||
      mediatorsRespondent.length > 0 ||
      !!c.judgeId);

  const showPublicPrefForm =
    (c.status === 'DECIDED' ||
      c.status === 'CLOSED' ||
      c.status === 'SOLVED' ||
      c.status === 'UNSOLVED' ||
      c.status === 'DISCARDED') &&
    (c.isAccuser || c.isRespondent);

  const publicPreferenceForm = showPublicPrefForm
    ? form(
        {
          method: 'POST',
          action: `/courts/cases/${encodeURIComponent(c.id)}/public`
        },
        label(i18n.courtsPublicPrefLabel),
        br(),
        select(
          { name: 'preference' },
          option(
            { value: 'YES', ...(c.myPublicPreference === true ? { selected: true } : {})},
            i18n.courtsPublicPrefYes
          ),
          option(
            { value: 'NO', ...(c.myPublicPreference === false ? { selected: true } : {})},
            i18n.courtsPublicPrefNo
          )
        ),
        br(),
        br(),
        button(
          { type: 'submit', class: 'create-button' },
          i18n.courtsPublicPrefSubmit
        )
      )
    : null;

  const respondentMediatorsForm = RespondentMediatorsForm(c);

  const canAddEvidence =
    c.isAccuser || c.isRespondent || c.isMediator || c.isJudge || c.isDictator;
  const canAnswer = c.isRespondent;
  const canIssueVerdict =
    ((methodKey(c.method) === 'JUDGE' && c.isJudge) ||
      (methodKey(c.method) === 'MEDIATION' && c.isMediator) ||
      (methodKey(c.method) === 'DICTATOR' && c.isDictator)) &&
    (c.status === 'OPEN' || c.status === 'IN_PROGRESS') &&
    !c.hasVerdict;
  const canProposeSettlement =
    (c.isAccuser || c.isRespondent || c.isMediator) &&
    methodKey(c.method) === 'MEDIATION' &&
    c.status === 'OPEN';
  const canOpenVote =
    (c.isAccuser || c.isRespondent) &&
    (methodKey(c.method) === 'POPULAR' || methodKey(c.method) === 'KARMATOCRACY') &&
    (c.status === 'OPEN' || c.status === 'IN_PROGRESS') &&
    !c.voteId;
  const canAcceptSettlement =
    (c.isAccuser || c.isRespondent) &&
    methodKey(c.method) === 'MEDIATION' &&
    (c.status === 'OPEN' || c.status === 'IN_PROGRESS') &&
    !!c.hasSettlement;
  const isNormalUser =
    !c.isAccuser &&
    !c.isRespondent &&
    !c.isMediator &&
    !c.isJudge &&
    !c.isDictator;
  const canSupport =
    isNormalUser &&
    (c.status === 'IN_PROGRESS' || c.status === 'OPEN');
  const canAssignJudge =
    methodKey(c.method) === 'JUDGE' &&
    !c.judgeId &&
    (c.isAccuser || c.isRespondent);

  return div(
    { class: 'card' },
    br(),
    div(
      { class: 'card-field' },
      span({ class: 'card-label' }, i18n.courtsThCase + ': '),
      span({ class: 'card-value' }, c.title || '')
    ),
    div({ class: 'card-chips-row' }, CourtsE2EChip()),
    div(
      { class: 'card-field' },
      span({ class: 'card-label' }, i18n.courtsThStatus + ': '),
      span({ class: 'card-value' }, String(c.status || ''))
    ),
    div(
      { class: 'card-field' },
      span({ class: 'card-label' }, i18n.courtsMethod + ': '),
      span({ class: 'card-value' }, methodLabel(c.method))
    ),
    c.answerBy
      ? div(
          { class: 'card-field' },
          span({ class: 'card-label' }, i18n.courtsThAnswerBy + ': '),
          span({ class: 'card-value' }, fmt(c.answerBy))
        )
      : null,
    c.evidenceBy
      ? div(
          { class: 'card-field' },
          span({ class: 'card-label' }, i18n.courtsThEvidenceBy + ': '),
          span({ class: 'card-value' }, fmt(c.evidenceBy))
        )
      : null,
    c.decisionBy
      ? div(
          { class: 'card-field' },
          span({ class: 'card-label' }, i18n.courtsThDecisionBy + ': '),
          span({ class: 'card-value' }, fmt(c.decisionBy))
        )
      : null,
    div(
      { class: 'table-wrap mt-2' },
      applyEl(table, { class: 'table table--centered' }, [
        thead(
          tr(
            th(i18n.courtsAccuser),
            th(i18n.courtsRespondent)
          )
        ),
        tbody(
          tr(
            td(accLinkFull),
            td(resLinkFull)
          )
        )
      ])
    ),
    showMediatorsTable
      ? div(
          { class: 'table-wrap mt-2 mediators-table' },
          applyEl(table, { class: 'table table--centered' }, [
            thead(
              tr(
                th(i18n.courtsThJudge),
                th(
                  i18n.courtsMediatorsAccuserLabel ||
                    i18n.courtsMediatorsLabel ||
                    'Accuser mediators'
                ),
                th(
                  i18n.courtsMediatorsRespondentLabel ||
                    i18n.courtsMediatorsLabel ||
                    'Respondent mediators'
                )
              )
            ),
            tbody(
              tr(
                td(judgeLinkFull),
                td(
                  mediatorLinksAccuser.length
                    ? mediatorLinksAccuser
                    : span('')
                ),
                td(
                  mediatorLinksRespondent.length
                    ? mediatorLinksRespondent
                    : span('')
                )
              )
            )
          ])
        )
      : null,

    c.supportCount
      ? div(
          { class: 'card-field' },
          span({ class: 'card-label' }, i18n.courtsSupportCount + ': '),
          span({ class: 'card-value' }, String(c.supportCount))
        )
      : null,
    showMetricsFlag
      ? div(
          { class: 'card-field' },
          span({ class: 'card-label' }, i18n.courtsVotesNeeded + ': '),
          span({ class: 'card-value' }, String(needed))
        )
      : null,
    showMetricsFlag
      ? div(
          { class: 'card-field' },
          span({ class: 'card-label' }, i18n.courtsVotesSlashTotal + ': '),
          span({ class: 'card-value' }, `${yes}/${total}`)
        )
      : null,
    c.voteId
      ? form(
          { method: 'GET', action: `/votes/${encodeURIComponent(c.voteId)}` },
          button({ type: 'submit', class: 'vote-btn' }, i18n.courtsOpenVote)
        )
      : null,
    canSupport ? SupportCaseForm(c.id || '') : null,
    publicPreferenceForm,
    respondentMediatorsForm,
    canAssignJudge ? JudgeAssignForm(c.id || '') : null,
    canAddEvidence ? EvidenceForm(c.id || '') : null,
    canAnswer ? AnswerForm(c.id || '') : null,
    canIssueVerdict ? VerdictForm(c.id || '') : null,
    canProposeSettlement ? SettlementForm(c.id || '') : null,
    canOpenVote ? OpenVoteForm(c.id || '') : null,
    canAcceptSettlement ? AcceptSettlementForm(c.id || '') : null
  );
};

const CasesList = (rows = []) => {
  const cards = rows.map(CaseCard);
  return div({ class: 'cards' }, ...cards);
};

const MyCasesList = (rows = []) => {
  const cards = rows.map(MyCaseCard);
  return div({ class: 'cards' }, ...cards);
};

const roleTextForCase = (c) => {
  if (c.isAccuser) return i18n.courtsRoleAccuser || 'Accuser';
  if (c.isRespondent) return i18n.courtsRoleDefence || 'Defence';
  if (c.isMediator) return i18n.courtsRoleMediator || 'Mediator';
  if (c.isJudge) return i18n.courtsRoleJudge || 'Judge';
  if (c.isDictator) return i18n.courtsRoleDictator || 'Dictator';
  return '';
};

const CasesTable = (rows = [], opts = {}) => {
  if (!rows.length) return div({ class: 'empty' }, p(i18n.courtsNoCases));
  const showRole = !!opts.showRole;
  const bodyRows = rows.map((c) => {
    const role = showRole ? roleTextForCase(c) : '';
    return tr(
      td(c.title || ''),
      td(
        c.accuser
          ? a(
              {
                class: 'user-link',
                href: `/author/${encodeURIComponent(c.accuser)}`
              },
              c.accuser
            )
          : ''
      ),
      td(methodLabel(c.method)),
      td(c.createdAt ? fmt(c.createdAt) : ''),
      showRole ? td(role) : null,
      td(
        c.id
          ? form(
              {
                method: 'GET',
                action: `/courts/cases/${encodeURIComponent(c.id)}`
              },
              button(
                { type: 'submit', class: 'link-button' },
                i18n.courtsViewDetailsShort ||
                  i18n.courtsViewDetails ||
                  'View'
              )
            )
          : ''
      )
    );
  });
  return div(
    { class: 'table-wrap' },
    applyEl(table, { class: 'table table--centered' }, [
      thead(
        tr(
          th(i18n.courtsThCase),
          th(i18n.courtsAccuser),
          th(i18n.courtsCaseMethod),
          th(i18n.courtsThCreatedAt),
          showRole ? th(i18n.courtsThRole || 'Role') : null,
          th(i18n.courtsThDetails || '')
        )
      ),
      applyEl(tbody, null, bodyRows)
    ])
  );
};

const NominationsTable = (nominations = [], currentUserId = '') => {
  if (!nominations || !nominations.length)
    return div({ class: 'empty' }, p(i18n.courtsNoNominations));
  const rows = nominations.map((n) => {
    const isSelf =
      currentUserId &&
      String(n.judgeId || '') === String(currentUserId || '');
    return tr(
      td(userLink(n.judgeId)),
      td(String(n.supports || 0)),
      td(fmt(n.createdAt)),
      td(
        isSelf
          ? span('')
          : form(
              {
                method: 'POST',
                action: `/courts/judges/${encodeURIComponent(n.id)}/vote`
              },
              button({ class: 'vote-btn' }, i18n.courtsThVote)
            )
      )
    );
  });
  return div(
    { class: 'table-wrap' },
    h2(i18n.courtsNominationsTitle),
    applyEl(table, { class: 'table table--centered' }, [
      thead(
        tr(
          th(i18n.courtsThJudge),
          th(i18n.courtsThSupports),
          th(i18n.courtsThDate),
          th(i18n.courtsThVote)
        )
      ),
      applyEl(tbody, null, rows)
    ])
  );
};

const JudgesSection = (nominations = [], currentUserId = '') => {
  const nomBlock = NominationsTable(nominations, currentUserId);
  return div(NominateJudgeForm(), nomBlock);
};

const HistoryList = (rows = []) => {
  if (!rows.length) return div({ class: 'empty' }, p(i18n.courtsNoHistory));
  const cards = rows.map((hh) => {
    const canShowDescription = hh.mine || hh.publicDetails;
    return div(
      { class: 'card' },
      br(),
      hh.method
        ? div(
            { class: 'card-field' },
            span({ class: 'card-label' }, i18n.courtsCaseMethod + ': '),
            span({ class: 'card-value' }, methodLabel(hh.method))
          )
        : null,
      hh.decidedAt
        ? div(
            { class: 'card-field' },
            span({ class: 'card-label' }, i18n.courtsThDecisionBy + ': '),
            span({ class: 'card-value' }, fmt(hh.decidedAt))
          )
        : null,
      div(
        { class: 'card-field' },
        span({ class: 'card-label' }, i18n.courtsThStatus + ': '),
        span({ class: 'card-value' }, String(hh.status || ''))
      ),
      h2(hh.title || ''),
      canShowDescription ? RichTextBlock(hh.description || '') : null,
      form(
        {
          method: 'GET',
          action: `/courts/cases/${encodeURIComponent(hh.id)}`
        },
        button({ type: 'submit', class: 'create-button' }, i18n.courtsViewDetails)
      )
    );
  });
  return div({ class: 'cards' }, ...cards);
};

const RulesContent = () => {
  const points = [
    i18n.courtsRulesIntro,
    i18n.courtsRulesLifecycle,
    i18n.courtsRulesRoles,
    i18n.courtsRulesEvidence,
    i18n.courtsRulesDeliberation,
    i18n.courtsRulesVerdict,
    i18n.courtsRulesAppeals,
    i18n.courtsRulesPrivacy,
    i18n.courtsRulesMisconduct,
    i18n.courtsRulesGlossary
  ];
  return div(
    { class: 'card' },
    h2(i18n.courtsRulesTitle),
    div({ class: 'rules-points' },
      points.filter(Boolean).map((t, i) =>
        div({ class: 'rules-point' },
          span({ class: 'rules-point-num' }, String(i + 1)),
          span({ class: 'rules-point-text' }, t)
        )
      )
    )
  );
};

const CaseSearch = (filter, search = '') =>
  div(
    { class: 'filters' },
    form(
      { method: 'GET', action: '/courts', class: 'filter-box' },
      input({ type: 'hidden', name: 'filter', value: filter }),
      input({
        type: 'text',
        name: 'search',
        placeholder: i18n.searchCasesPlaceholder,
        value: search || '',
        class: 'filter-box__input'
      }),
      div({ class: 'filter-box__controls' },
        button({ type: 'submit', class: 'filter-box__button' }, i18n.searchButton)
      )
    )
  );

const CaseDetailsBlock = (c) => {
  if (!c) return div({ class: 'empty' }, p(i18n.courtsNoCases));
  const canShowFull = c.mine || c.publicDetails;
  const accLink = UserLinkFull(c.accuser);
  const resLink = UserLinkFull(c.respondent || c.respondentId);
  const judgeValue = c.judgeId
    ? UserLinkFull(c.judgeId)
    : span(i18n.courtsJudgeNotAssigned || '-');
  const mediatorsAccuser = Array.isArray(c.mediatorsAccuser)
    ? c.mediatorsAccuser
    : [];
  const mediatorsRespondent = Array.isArray(c.mediatorsRespondent)
    ? c.mediatorsRespondent
    : [];
  const mediatorLinksAccuser = mediatorsAccuser.map((mId, idx) =>
    span(
      { class: 'mediator' },
      userLink(mId),
      idx < mediatorsAccuser.length - 1 ? span(', ') : null
    )
  );
  const mediatorLinksRespondent = mediatorsRespondent.map((mId, idx) =>
    span(
      { class: 'mediator' },
      userLink(mId),
      idx < mediatorsRespondent.length - 1 ? span(', ') : null
    )
  );
  const showMediatorsTable =
    c.method && (mediatorsAccuser.length || mediatorsRespondent.length);
  const evidences = Array.isArray(c.evidences) ? c.evidences : [];
  const answers = Array.isArray(c.answers) ? c.answers : [];
  const settlements = Array.isArray(c.settlements) ? c.settlements : [];

  const evidenceSideLabel = (e) => {
    const side = String((e && (e.side || e.role)) || '').toUpperCase();
    if (side === 'ACCUSER') {
      return i18n.courtsEvidenceSideAccuser || 'Accuser evidence';
    }
    if (side === 'RESPONDENT' || side === 'DEFENCE' || side === 'DEFENSE') {
      return i18n.courtsEvidenceSideRespondent || 'Defence evidence';
    }
    return i18n.courtsEvidenceSideUnknown || '';
  };

  return div(
    { class: 'card case-details-card' },
    br(),
    div(
      { class: 'card-header' },
      div(
        { class: 'card-header__meta' },
        h2(c.title || ''),
        div({ class: 'card-chips-row' }, CourtsE2EChip()),
        c.method
          ? div(
              { class: 'card-field' },
              span({ class: 'card-label' }, i18n.courtsCaseMethod + ': '),
              span({ class: 'card-value' }, methodLabel(c.method))
            )
          : null,
        div(
          { class: 'card-field' },
          span({ class: 'card-label' }, i18n.courtsThJudge + ': '),
          span({ class: 'card-value' }, judgeValue)
        ),
        div(
          { class: 'card-field' },
          span({ class: 'card-label' }, i18n.courtsThStatus + ': '),
          span({ class: 'card-value' }, String(c.status || ''))
        ),
        c.createdAt
          ? div(
              { class: 'card-field' },
              span({ class: 'card-label' }, i18n.courtsThCreatedAt + ': '),
              span({ class: 'card-value' }, fmt(c.createdAt))
            )
          : null,
        c.decidedAt
          ? div(
              { class: 'card-field' },
              span({ class: 'card-label' }, i18n.courtsThDecisionBy + ': '),
              span({ class: 'card-value' }, fmt(c.decidedAt))
            )
          : null
      )
    ),
    div(
      { class: 'table-wrap mt-2' },
      applyEl(table, { class: 'table table--centered' }, [
        thead(
          tr(
            th(i18n.courtsAccuser),
            th(i18n.courtsRespondent)
          )
        ),
        tbody(
          tr(
            td(accLink),
            td(resLink)
          )
        )
      ])
    ),
    showMediatorsTable
      ? div(
          { class: 'table-wrap mt-2 mediators-table' },
          applyEl(table, { class: 'table table--centered' }, [
            thead(
              tr(
                th(
                  i18n.courtsMediatorsAccuserLabel ||
                    i18n.courtsMediatorsLabel ||
                    'Accuser mediators'
                ),
                th(
                  i18n.courtsMediatorsRespondentLabel ||
                    i18n.courtsMediatorsLabel ||
                    'Respondent mediators'
                )
              )
            ),
            tbody(
              tr(
                td(
                  mediatorLinksAccuser.length
                    ? mediatorLinksAccuser
                    : span('')
                ),
                td(
                  mediatorLinksRespondent.length
                    ? mediatorLinksRespondent
                    : span('')
                )
              )
            )
          ])
        )
      : null,
    canShowFull ? RichTextBlock(c.description || '') : null,
    !canShowFull
      ? div(
          { class: 'card-field' },
          p(i18n.courtsDetailsNotPublic)
        )
      : null,
    canShowFull && evidences.length
      ? div(
          { class: 'card-section evidences-section' },
          h2(i18n.courtsDetailsEvidenceTitle),
          ...evidences.map((e) => {
            const bodyChildren = [];
            if (e.text && String(e.text).trim()) {
              bodyChildren.push(RichTextBlock(e.text));
            }
            if (e.link && String(e.link).trim()) {
              bodyChildren.push(
                a(
                  {
                    class: 'evidence-link',
                    href: e.link,
                    target: '_blank',
                    rel: 'noopener noreferrer'
                  },
                  e.link
                )
              );
            }
            if (e.imageUrl && String(e.imageUrl).trim()) {
              bodyChildren.push(
                br(),br(),
                img({
                  class: 'evidence-image',
                  src: `/blob/${encodeURIComponent(e.imageUrl)}`,
                  alt: 'evidence'
                })
              );
            }
            if (!bodyChildren.length) {
              bodyChildren.push(span(''));
            }
            const sideLabel = evidenceSideLabel(e);
            const dateText = fmt(e.createdAt);
            const dateWithSide = sideLabel
              ? dateText + ' · ' + sideLabel
              : dateText;
            return div(
              { class: 'evidence-item' },
              div(
                { class: 'evidence-date' },
                dateWithSide
              ),
              div(
                { class: 'evidence-body' },
                ...bodyChildren
              )
            );
          })
        )
      : null,
    canShowFull && answers.length
      ? div(
          { class: 'card-section answers-section' },
          h2(i18n.courtsDetailsAnswersTitle),
          ...answers.map((aItem) => {
            const stanceKey = methodKey(aItem.stance);
            const stanceLabel =
              stanceKey && i18n[`courtsStance${stanceKey}`]
                ? i18n[`courtsStance${stanceKey}`]
                : aItem.stance || '';
            const dateText = fmt(aItem.createdAt);
            const metaText = stanceLabel
              ? dateText + ' · ' + stanceLabel
              : dateText;
            return div(
              { class: 'answer-item' },
              div(
                { class: 'answer-meta' },
                metaText
              ),
              RichTextBlock(aItem.text || '')
            );
          })
        )
      : null,
    canShowFull && c.verdict
      ? div(
          { class: 'card-section verdict-section' },
          h2(i18n.courtsDetailsVerdictTitle),
          div(
            { class: 'card-field' },
            span({ class: 'card-label' }, i18n.courtsVerdictResult + ': '),
            span({ class: 'card-value' }, c.verdict.result || '')
          ),
          c.verdict.orders
            ? div(
                { class: 'card-field' },
                span(
                  { class: 'card-label' },
                  i18n.courtsVerdictOrders + ': '
                ),
                RichTextBlock(c.verdict.orders || '')
              )
            : null
        )
      : null,
    canShowFull && settlements.length
      ? div(
          { class: 'card-section settlements-section' },
          h2(i18n.courtsDetailsSettlementsTitle),
          ...settlements.map((sItem) =>
            div(
              { class: 'settlement-item' },
              div(
                { class: 'settlement-date' },
                fmt(sItem.createdAt)
              ),
              RichTextBlock(sItem.terms || '')
            )
          )
        )
      : null
  );
};

const courtsView = async (state) => {
  const {
    filter = 'cases',
    cases = [],
    myCases = [],
    history = [],
    nominations = [],
    search = '',
    userId = ''
  } = state;
  return template(
    i18n.courtsTitle,
    section(
      div(
        { class: 'tags-header' },
        h2(i18n.courtsTitle),
        p(i18n.courtsDescription)
      ),
      Tabs(filter),
      filter === 'cases' ? CaseSearch(filter, search) : null
    ),
    section(
      filter === 'cases' ? CasesTable(cases) : null,
      filter === 'mycases'
        ? myCases.length
          ? CasesTable(myCases, { showRole: true })
          : div({ class: 'empty' }, p(i18n.courtsNoMyCases))
        : null,
      filter === 'actions'
        ? myCases.length
          ? MyCasesList(myCases)
          : div({ class: 'empty' }, p(i18n.courtsNoMyCases))
        : null,
      filter === 'judges' ? JudgesSection(nominations, userId) : null,
      filter === 'history' ? HistoryList(history) : null,
      filter === 'rules' ? RulesContent() : null,
      filter === 'open' ? CaseForm(state.prefill || {}) : null
    )
  );
};

const courtsCaseView = async (state) => {
  const { caseData } = state;
  return template(
    i18n.courtsTitle,
    section(
      div(
        { class: 'tags-header' },
        h2(i18n.courtsTitle),
        p(i18n.courtsDescription)
      ),
      Tabs('cases')
    ),
    section(CaseDetailsBlock(caseData))
  );
};

module.exports = { courtsView, courtsCaseView };

