// PartnerDetailV6 — 取引先詳細(K18-31)。池田さん版(reference/ikeda-2026-09-16/screens/marurou/Screens.jsx の
// PartnerDetail)の 2 カラムに組み直したもの。以前の本体は Screens.jsx の PartnerDetail で、いまはここを呼ぶだけ。
//
//   左: 取引先カード(フリガナ・電話・メール・社内担当・取引・精算・契約・確認済み・住所(請求先)・本社・備考・
//       担当者のチップ「名前(役割)」)と、進行中の案件
//   右: 依頼者規定(取引条件・初動対応注意点・管理エリア・管理会社側システム・規定精算(調査/復旧)・
//       保険/オーナーの窓口・請求パターン)・支店・連絡
//
// 値はどれも rpc_list_partners の行に載って来る(専用の詳細 RPC は無い。0101/0106/0114〜0116)。
// 池田さん版から変えたところ(docs/21 §0「見た目と使い勝手だけ取り込み、main の機能は残す」):
//   ・LINE のボタンは置かない(決-37: LINE は居住者とのやりとりだけ)。電話・メール・SMS・Slack は残す。
//   ・「連絡(案件横断)」の履歴は持たない(取引先直下の連絡は K18-34/35/36 の宿題)。連絡の記録は今までどおり
//     先頭の進行中の案件に残し、残せないときは理由を出して成功扱いにしない(案件詳細-5)。
//   ・架空の取引履歴(池田さん版の HIST)は出さない。
//   ・確認済みはここで付け外す(K18-33・OrgFields.jsx の OrgVerifyControl)。社内担当・契約の編集は管理画面。

/* 上にラベル・下に値の欄(池田さん版の Field と同じ並び)。span は横に何マス使うか。 */
function PdField({ label, children, span, mono }) {
  return (
    <div style={{ display: "flex", flexDirection: "column", gap: 2, minWidth: 0, gridColumn: span ? "span " + span : undefined }}>
      <span style={{ fontSize: "var(--text-caption)", fontWeight: 600, letterSpacing: "0.04em", color: "var(--muted-foreground)" }}>{label}</span>
      <span className={mono ? "mono" : undefined} style={{ fontSize: "var(--text-body-md)", minWidth: 0, wordBreak: "break-word" }}>{children}</span>
    </div>
  );
}
/* 見出しつきのカード。 */
function PdCard({ title, sub, children, pad = 14 }) {
  return (
    <AfCard pad={0} style={{ overflow: "hidden" }}>
      <div style={{ padding: "10px 14px", background: "var(--accent)", borderBottom: "1px solid var(--border)", fontSize: "var(--text-body-md)", fontWeight: 700 }}>
        <span>{title}</span>{sub ? <span style={{ fontSize: "var(--text-caption)", fontWeight: 500, color: "var(--foreground-subtle)", marginLeft: 8 }}>{sub}</span> : null}
      </div>
      <div style={{ padding: pad }}>{children}</div>
    </AfCard>
  );
}
const pdDash = <span style={{ color: "var(--foreground-subtle)" }}>—</span>;
const pdOrgLabel = (o) => (o && o.name ? o.name + (o.branchName ? "（" + o.branchName + "）" : "") : "");

function PartnerDetailV6({ partner, onBack, onContact, onOpenCase, onToast }) {
  const [contextStatus, setContextStatus] = React.useState({ status: "idle" });
  const [remoteRelated, setRemoteRelated] = React.useState([]);
  const [relatedStatus, setRelatedStatus] = React.useState("idle");
  const p = partner || {};
  React.useEffect(() => {
    if (!p.id || !window.MarurouCloud || !window.MarurouCloud.listPartnerCaseIds) return;
    let alive = true;
    setRelatedStatus("loading");
    window.MarurouCloud.listPartnerCaseIds(p.id).then(rows => {
      if (!alive) return;
      setRemoteRelated((rows || []).map(x => ({ id:x.dbId, dbId:x.dbId, prop:x.name,
        m:{ accepted:x.accepted, stage:"", dueDone:"—" } })));
      setRelatedStatus("ready");
    }).catch(() => { if (alive) { setRelatedStatus("error"); setRemoteRelated([]); } });
    return () => { alive = false; };
  }, [p.id]);
  if (!partner) return null;

  const meta = window.BV_CASEMETA || {};
  // 進行中(seed の未完了)だけ。完了済みは盤面に無いので、件数は p.cases(累計)と並べて出す。
  const localRelated = ((window.MStore && window.MStore.get().cases) || [])
    .filter(c => c.client===p.name || (c.parties||[]).some(x => x && x.name===p.name))
    .map(c => ({ id:c.id, dbId:c.dbId, prop:c.name, m: meta[c.id] || { accepted:String(c.accepted||"").slice(5), stage:"", dueDone:c.dueDone||"—" } }));
  const related = [...localRelated, ...remoteRelated.filter(x => !localRelated.some(y => y.dbId && x.dbId && y.dbId === x.dbId))];
  const isVendor = p.kind === "業者";
  const dealLabel = isVendor ? "発注先" : p.cont==="継続" ? "継続" : p.cont==="スポット" ? "スポット" : null;
  const dealTone = isVendor ? "brand" : p.cont==="継続" ? "success" : p.cont==="スポット" ? "survey" : "neutral";
  const contacts = Array.isArray(p.contacts) ? p.contacts : [];
  const branches = Array.isArray(p.branches) ? p.branches : [];
  const COLS = "1.6fr 62px 52px 1fr 66px";

  /* 連絡の記録: 取引先詳細には案件が無い(案件詳細-5と同じ理由)。先頭の関連する進行中案件へ
     記録を1件足す(PhoneLink・下の連絡ボタン共通)。関連案件が無ければ何もしない。 */
  const logContactToRelatedCase = (label, body) => {
    if (!related.length || !window.MStore) return null;
    const caseId = related[0].id;
    const when = (typeof scTodayMd === "function") ? scTodayMd() : ((d)=>{ return (d.getMonth()+1)+"/"+d.getDate(); })(new Date());
    window.MStore.updateCase(caseId, c => {
      let party = (c.parties||[]).find(x => x && x.name === p.name);
      if (!party) {
        party = { role: isVendor ? "業者" : "依頼者", name: p.name, wait: null, log: [] };
        c.parties = [...(c.parties||[]), party];
      }
      party.log = [{ d: when, dir: "out", t: label + "：" + (body || "連絡") }, ...(party.log || [])];
    });
    return caseId;
  };
  /* PhoneLinkのonCall: 押した瞬間に「Zoomで発信」の記録を1件作る。関連案件が無ければ記録は残らないが、
     発信リンク自体は押せる(Zoom側の発信は止めない)。 */
  const onPhoneCall = (who, phone) => {
    const caseId = logContactToRelatedCase("電話", "Zoomで発信: " + who + " " + phone);
    onToast && onToast(caseId
      ? who + "への発信を案件 " + caseId + " に記録しました"
      : who + "へ発信しました(関連する進行中案件が無いため記録は残せません)");
  };
  /* 連絡モーダル(ContactModal)の onSent。関連案件の関係者情報を取ってから記録する。取れなければ
     reject して成功扱いにしない(モーダルは閉じず、赤帯に理由が出る)。 */
  const onSent = async (label, body) => {
    if (!related.length || !window.MStore) {
      const error = new Error("関連案件が読み込まれていません。案件を取得してから記録してください。");
      onToast && onToast(error.message);
      throw error;
    }
    let caseId = related[0].id;
    let relatedCase = window.MStore.case(caseId);
    if (!relatedCase && related[0].dbId && window.MStore.ensureCaseLoaded) {
      relatedCase = await window.MStore.ensureCaseLoaded(related[0].dbId);
      caseId = relatedCase && relatedCase.id;
    }
    if (!relatedCase || !caseId || !relatedCase.dbId || !window.MStore.ensureCaseDetailContext) {
      const error = new Error("関連案件の関係者情報を取得できないため、記録できません。");
      onToast && onToast(error.message);
      throw error;
    }
    setContextStatus({ status:"loading" });
    try {
      await window.MStore.ensureCaseDetailContext(caseId, relatedCase.dbId);
      setContextStatus({ status:"ready" });
    } catch (error) {
      setContextStatus({ status:"error", error });
      onToast && onToast("関連案件の関係者情報を取得できませんでした。再試行してください。");
      throw error;
    }
    const when = (typeof scTodayMd === "function") ? scTodayMd() : ((d)=>{ return (d.getMonth()+1)+"/"+d.getDate(); })(new Date());
    window.MStore.updateCase(caseId, c => {
      let party = (c.parties||[]).find(x => x && x.name === p.name);
      if (!party) {
        party = { role: isVendor ? "業者" : "依頼者", name: p.name, wait: null, log: [] };
        c.parties = [...(c.parties||[]), party];
      }
      party.log = [{ d: when, dir: "out", t: label + "：" + (body || "連絡") }, ...(party.log || [])];
    });
    onToast && onToast(p.name + " への記録を案件 " + caseId + " に残しました");
  };

  const ownerName = (window.orgOwnerName && window.orgOwnerName(p)) || "";
  const contractLabel = (window.orgContractLabel && window.orgContractLabel(p)) || "";
  // 依頼者規定: 業者には出さない(規定は依頼者の約束事)。業者でも値が入っていれば出す(入れた値を隠さない)。
  const RULES = [
    ["取引条件", p.tradeTerms, 2], ["初動対応注意点", p.firstResponseNotes, 2],
    ["管理エリア", p.serviceArea], ["管理会社側システム", p.clientSystemName],
    ["規定精算（調査）", p.defaultSettlementSurvey], ["規定精算（復旧）", p.defaultSettlementRepair],
    ["保険窓口", p.insuranceWindow], ["オーナー窓口", p.ownerWindow],
    ["請求パターン", p.contract],
  ];
  const showRules = !isVendor || RULES.some(([, v]) => v);

  return (
    <div style={{ padding:"18px 24px 32px 20px", maxWidth:1200 }}>
      <ScBack onClick={onBack} label="取引先一覧" />
      <div style={{ display:"flex", alignItems:"center", gap:10, flexWrap:"wrap" }}>
        <h1 style={{ margin:0, fontSize:"var(--text-display-md)", fontWeight:700, letterSpacing:"var(--tracking-tight)" }}>{p.name}</h1>
        {p.branchName ? <ScChip>支店名 {p.branchName}</ScChip> : null}
        <ScChip>{p.type}</ScChip>
        <ScChip tone="brand">{p.kind}</ScChip>
        {dealLabel && <ScChip tone={dealTone}>{dealLabel}</ScChip>}
      </div>
      <div style={{ fontSize:"var(--text-body-sm)", color:"var(--muted-foreground)", marginTop:4 }}>
        取引実績から導出（マスタに状態カラムを持たない・昇格操作なし）
      </div>

      <div style={{ display:"flex", gap:12, marginTop:12, alignItems:"flex-start", flexWrap:"wrap" }}>
        {/* ── 左: 取引先カードと進行中の案件 ── */}
        <div style={{ flex:"1.6 1 520px", minWidth:0, display:"flex", flexDirection:"column", gap:12 }}>
          <PdCard title="取引先">
            <div style={{ display:"grid", gridTemplateColumns:"repeat(auto-fill, minmax(180px, 1fr))", gap:"12px 16px" }}>
              <PdField label="フリガナ">{p.nameKana || pdDash}</PdField>
              <PdField label="電話">{p.tel
                ? <PhoneLink phone={p.tel} name={p.name} onCall={()=>onPhoneCall(p.name, p.tel)} />
                : pdDash}</PdField>
              <PdField label="メール">{p.email || pdDash}</PdField>
              {/* K18-32(0114): 社内担当。編集は管理画面の取引先タブ */}
              <PdField label="社内担当">{ownerName || pdDash}</PdField>
              <PdField label="取引">{dealLabel || pdDash}</PdField>
              <PdField label={isVendor ? "支払" : "精算"}>{p.contract || pdDash}</PdField>
              {/* K18-33(0115): 契約状態(空は不明)。編集は管理画面の取引先タブ */}
              <PdField label="契約">{contractLabel || <span style={{ color:"var(--foreground-subtle)" }}>不明</span>}</PdField>
              <PdField label="関連案件"><span className="mono" style={{ fontWeight:700 }}>{p.cases||0}</span> 件
                <span style={{ fontSize:"var(--text-caption)", color:"var(--foreground-subtle)", marginLeft:6 }}>うち進行中 {related.length} 件</span></PdField>
              <PdField label="区分">{p.kind==="顧客"?"請求実績あり＝顧客":isVendor?"発注実績あり＝業者":"請求・発注なし＝関係者"}</PdField>
              {/* K18-03: 取込元が SF の請求先住所(Billing*)なのでラベルで明示する(列は既存の address) */}
              <PdField label="住所(請求先)" span={2}>{p.address || pdDash}</PdField>
              {/* K18-09: 本社(親取引先) */}
              <PdField label="本社">{p.parent ? pdOrgLabel(p.parent) : pdDash}</PdField>
              {/* K18-33(0115): 確認済みはここで付け外す(日時と人はサーバが決める) */}
              <PdField label="確認済み" span={2}>{window.OrgVerifyControl ? <window.OrgVerifyControl partner={p} onToast={onToast} /> : pdDash}</PdField>
              <div style={{ gridColumn:"1 / -1" }}>
                <PdField label="担当者">{contacts.length
                  ? <span style={{ display:"inline-flex", gap:6, flexWrap:"wrap" }}>{contacts.map((c,i) => (
                      <span key={i} style={{ display:"inline-flex", alignItems:"center", gap:6, padding:"2px 8px", borderRadius:"var(--radius-full)",
                        border:"1px solid var(--border)", background:"var(--muted)", fontSize:"var(--text-body-sm)" }}>
                        {(c.name||"")}{c.role ? "（"+c.role+"）" : c.title ? "（"+c.title+"）" : ""}
                        {c.phone ? <PhoneLink phone={c.phone} name={c.name||p.name} onCall={()=>onPhoneCall(c.name||p.name, c.phone)} /> : null}
                      </span>))}</span>
                  : pdDash}</PdField>
              </div>
              {/* K18-09: 備考(SF の 備考/説明/課題/特記 を見出しつきで結合した値。編集は管理画面の取引先タブ)。
                  長文が多い(SF の 4 項目の結合)ので高さを抑えてスクロール。担当者の欄を先に置く */}
              <div style={{ gridColumn:"1 / -1" }}>
                <PdField label="備考"><span style={{ display:"block", whiteSpace:"pre-wrap", lineHeight:1.6, maxHeight:"16em", overflowY:"auto" }}>{p.notes || pdDash}</span></PdField>
              </div>
            </div>
          </PdCard>

          <AfCard pad={0} style={{ overflow:"hidden" }}>
            <div style={{ padding:"10px 14px", background:"var(--accent)", borderBottom:"1px solid var(--border)", fontSize:"var(--text-body-md)", fontWeight:700 }}>
              進行中の案件 <span className="mono" style={{ color:"var(--muted-foreground)", fontWeight:500 }}>{related.length}</span>
              <span style={{ fontSize:"var(--text-caption)", fontWeight:500, color:"var(--foreground-subtle)", marginLeft:8 }}>この画面に載る未完了だけ</span>
            </div>
            <div style={{ display:"grid", gridTemplateColumns:COLS, gap:8, padding:"7px 14px", borderBottom:"1px solid var(--border)" }}>
              {["物件・案件名","受付日","段階","案件No.","完了予定"].map(h=>(
                <span key={h} style={{ fontSize:"var(--text-caption)", fontWeight:600, letterSpacing:"0.03em", color:"var(--muted-foreground)" }}>{h}</span>
              ))}
            </div>
            {related.length===0 && <div style={{ padding:16, fontSize:"var(--text-body-md)", color:"var(--foreground-subtle)" }}>該当なし</div>}
            {related.map((x,i)=>(
              <button key={x.id} onClick={()=>onOpenCase&&onOpenCase(x)} style={{ all:"unset", boxSizing:"border-box", width:"100%",
                display:"grid", gridTemplateColumns:COLS, gap:8, padding:"10px 14px", cursor:"pointer", alignItems:"center",
                fontFamily:"var(--font-sans)", borderBottom:i<related.length-1?"1px solid var(--border)":"none",
                transition:"background var(--duration-fast) var(--easing)" }}
                onMouseEnter={e=>e.currentTarget.style.background="var(--accent)"}
                onMouseLeave={e=>e.currentTarget.style.background="transparent"}>
                <span style={{ fontSize:"var(--text-body-md)", fontWeight:600 }}>{x.prop}</span>
                <span className="mono" style={{ fontSize:"var(--text-body-sm)", color:"var(--muted-foreground)" }}>{x.m.accepted||"—"}</span>
                <ScChip tone={x.m.stage==="工事"?"brand":x.m.stage==="調査"?"survey":x.m.stage==="完了"?"success":"neutral"}>{x.m.stage||"受付"}</ScChip>
                <span className="code" style={{ fontSize:"var(--text-body-sm)", color:"var(--brand)" }}>{x.id}</span>
                <span className="mono" style={{ fontSize:"var(--text-body-sm)", color:"var(--muted-foreground)" }}>{x.m.dueDone||"—"}</span>
              </button>
            ))}
            {relatedStatus==="error" && <div role="status" style={{ padding:"8px 14px", fontSize:"var(--text-caption)", color:"var(--muted-foreground)" }}>関連案件を取得できませんでした。再試行してください。</div>}
          </AfCard>
        </div>

        {/* ── 右: 依頼者規定・支店・連絡 ── */}
        <div style={{ flex:"1 1 300px", minWidth:0, display:"flex", flexDirection:"column", gap:12 }}>
          {showRules && <PdCard title="依頼者規定" sub="編集は管理画面の取引先タブ">
            <div style={{ display:"grid", gridTemplateColumns:"repeat(2, minmax(0, 1fr))", gap:"10px 14px" }}>
              {RULES.map(([label, v, span]) => (
                <PdField key={label} label={label} span={span}>
                  {v ? <span style={{ whiteSpace:"pre-wrap", lineHeight:1.6 }}>{v}</span> : pdDash}
                </PdField>
              ))}
            </div>
          </PdCard>}

          {/* K18-09: 支店一覧(自分を親にする取引先)。無い取引先(7,400 社余り)には出さない。 */}
          {branches.length>0 && <PdCard title="支店" sub={branches.length + " 件"} pad={0}>
            {branches.map((b,i) => (
              <div key={b.id||i} style={{ padding:"9px 14px", borderBottom:i<branches.length-1?"1px solid var(--border)":"none" }}>
                <div style={{ fontSize:"var(--text-body-md)", fontWeight:600 }}>{pdOrgLabel(b)}</div>
                {b.tel ? <div className="mono" style={{ fontSize:"var(--text-body-sm)", color:"var(--muted-foreground)" }}>{b.tel}</div> : null}
              </div>
            ))}
          </PdCard>}

          <PdCard title="連絡" sub="記録は先頭の進行中案件に残ります">
            <div style={{ display:"flex", flexDirection:"column", gap:8 }}>
              {/* 決-37: LINE は居住者とのやりとりだけ。取引先には出さない */}
              <div style={{ display:"flex", gap:6, flexWrap:"wrap" }}>
                {["電話","メール","SMS","Slack"].map(a=>(
                  <AfButton key={a} size="sm" onClick={()=>onContact&&onContact({ name:p.name, ch:a, onSent })}>{a}</AfButton>
                ))}
              </div>
              {contextStatus.status!=="idle" && contextStatus.status!=="ready" && <div role="status" style={{ fontSize:"var(--text-caption)", color:"var(--muted-foreground)" }}>
                {contextStatus.status==="loading" ? "関連案件の関係者を読み込み中…" : "関連案件の関係者を取得できませんでした。連絡記録は作成していません。"}
              </div>}
              {!related.length && relatedStatus!=="loading" && (
                <div style={{ fontSize:"var(--text-caption)", color:"var(--foreground-subtle)" }}>
                  関連する進行中案件が無いときは、連絡モーダルの記録は案件へ紐づけられません。
                </div>
              )}
              <div style={{ fontSize:"var(--text-caption)", color:"var(--foreground-subtle)" }}>
                案件をまたいだ連絡の一覧(取引先直下の記録)は、まだありません。
              </div>
            </div>
          </PdCard>
        </div>
      </div>
    </div>
  );
}

Object.assign(window, { PartnerDetailV6, PdField, PdCard });
