/* Workspace settings and the team — the two staged screens in this product.
   Commit model: STAGED, both of them. Every control is a form field, nothing
   applies until Save, Save and Cancel are disabled until dirty, and errors render
   on submission rather than on first paint. No instant control appears on either
   screen.
   Data state: one branch — populated.
   Entitlements gate controls, not copy: the sending-domain field only offers
   domains that pass all three DNS checks, and says which ones it left out and
   why. On the team screen a role change moves the approval badge in the sidebar,
   because both read ROLE_CAN_APPROVE. */
(() => {
  const {
    Table, TableHeader, TableBody, TableRow, TableHead, TableCell,
    Field, FieldLabel, FieldDescription, FieldError, Input, Select, Avatar, Badge, Button,
  } = window.OriginDesignSystem_7c998b;

  function WorkspaceSettingsScreen({ workspace, data, onSave }) {
    const initial = {
      name: workspace.name,
      sendingDomainId: workspace.sendingDomainId,
      replyTo: workspace.replyTo,
      timezone: workspace.timezone,
    };
    const [draft, setDraft] = React.useState(initial);
    const [submitted, setSubmitted] = React.useState(false);
    React.useEffect(() => { setDraft(initial); setSubmitted(false); }, [workspace]);

    const offered = authenticatedDomains(data.domains);
    const excluded = data.domains.filter((d) => !domainIsAuthenticated(d));

    const errors = {};
    if (draft.name.trim().length < 2) errors.name = "Name the workspace — at least two characters.";
    if (!/^[^@\s]+@[^@\s]+\.[^@\s]+$/.test(draft.replyTo)) errors.replyTo = "Enter a valid email address.";
    const valid = Object.keys(errors).length === 0;
    const dirty = Object.keys(initial).some((key) => initial[key] !== draft[key]);
    const set = (patch) => setDraft((d) => Object.assign({}, d, patch));

    return (
      <>
        <PageHeader path="/settings" title="Workspace settings" />

        <div className="md-form md-form--one">
          <Field>
            <FieldLabel htmlFor="cd-ws-name">Workspace name</FieldLabel>
            <Input id="cd-ws-name" value={draft.name} invalid={submitted && !!errors.name} onChange={(e) => set({ name: e.target.value })} />
            {submitted && errors.name ? <FieldError>{errors.name}</FieldError> : <FieldDescription>Shown in the sidebar and on every sign-in screen.</FieldDescription>}
          </Field>

          <Field>
            <FieldLabel>Sending domain</FieldLabel>
            <Select
              items={offered.map((d) => ({ value: d.id, label: d.domain }))}
              value={draft.sendingDomainId}
              aria-label="Sending domain"
              onValueChange={(value) => set({ sendingDomainId: value })}
            />
            <FieldDescription>
              {excluded.length
                ? excluded.map((d) => d.domain).join(" and ") + " " + (excluded.length === 1 ? "is" : "are") + " not offered — " + (excluded.length === 1 ? "it does" : "they do") + " not pass all three DNS checks. Deliverability says which."
                : "Every domain on this workspace passes all three DNS checks."}
            </FieldDescription>
          </Field>

          <Field>
            <FieldLabel htmlFor="cd-ws-reply">Reply-to address</FieldLabel>
            <Input id="cd-ws-reply" type="email" value={draft.replyTo} invalid={submitted && !!errors.replyTo} onChange={(e) => set({ replyTo: e.target.value })} />
            {submitted && errors.replyTo ? <FieldError>{errors.replyTo}</FieldError> : <FieldDescription>Where replies to every send land. It does not have to be on the sending domain.</FieldDescription>}
          </Field>

          <Field>
            <FieldLabel>Time zone</FieldLabel>
            <Select items={TIMEZONES} value={draft.timezone} aria-label="Time zone" onValueChange={(value) => set({ timezone: value })} />
            <FieldDescription>Every send time and every journey wait is read in this zone.</FieldDescription>
          </Field>
        </div>

        <FormBar
          dirty={dirty && valid}
          label="Save workspace"
          note={dirty
            ? "Nothing is applied until you save. " + data.broadcasts.filter((b) => !BROADCAST_FLAGS.countsTowardDelivery(b)).length + " unsent broadcasts would send from " + domainName(data.domains, draft.sendingDomainId) + "."
            : "Everything sends from " + domainName(data.domains, workspace.sendingDomainId) + ", with replies to " + workspace.replyTo + "."}
          onCancel={() => { setDraft(initial); setSubmitted(false); }}
          onSave={() => { setSubmitted(true); if (valid) onSave(draft); }}
        />
      </>
    );
  }

  function TeamScreen({ data, viewer, onSave, onInvite }) {
    const initial = data.members.map((m) => ({ id: m.id, teamRole: m.teamRole }));
    const [rows, setRows] = React.useState(initial);
    React.useEffect(() => { setRows(initial); }, [data.members]);

    const memberOf = (id) => data.members.find((m) => m.id === id) || {};
    const dirty = rows.some((row) => (initial.find((r) => r.id === row.id) || {}).teamRole !== row.teamRole);
    /* An invited person holds a role but cannot use it until they accept, so they
       are not counted here — the qualifier says how many are waiting. */
    const approvers = rows.filter((row) => ROLE_CAN_APPROVE[row.teamRole] && !memberOf(row.id).invited);
    const pendingApprovers = rows.filter((row) => ROLE_CAN_APPROVE[row.teamRole] && memberOf(row.id).invited);
    const invited = data.members.filter((m) => m.invited);
    const wouldStrand = approvers.length === 0;
    const set = (id, teamRole) => setRows((list) => list.map((r) => (r.id === id ? Object.assign({}, r, { teamRole: teamRole }) : r)));

    return (
      <>
        <PageHeader
          path="/settings/team"
          title="Team and roles"
          actions={<Button size="sm" onClick={onInvite}><Icon name="user-plus" />Invite teammate</Button>}
        />

        <Figures three items={[
          {
            label: "People",
            value: formatCount(data.members.length),
            qualifier: TEAM_ROLES.map((role) => {
              const n = rows.filter((r) => r.teamRole === role.value).length;
              return n ? n + " " + role.label.toLowerCase() + (n === 1 ? "" : "s") : null;
            }).filter(Boolean).join(" · ") + (invited.length ? " · " + invited.length + " not accepted yet" : ""),
          },
          {
            label: "Can approve a send",
            value: formatCount(approvers.length),
            qualifier: (approvers.length
              ? approvers.map((row) => memberName(data.members, row.id)).join(" · ")
              : "Nobody could approve anything — a send would sit in review forever")
              + (pendingApprovers.length ? " · " + pendingApprovers.length + " more once they accept their invitation" : ""),
          },
          {
            label: "Waiting on an approver",
            value: formatCount(broadcastsInReview(data.broadcasts).length),
            qualifier: (() => {
              const yours = broadcastsToReview(data.broadcasts, viewer).length;
              return formatCount(yours) + (yours === 1 ? " of them is waiting on you" : " of them are waiting on you");
            })(),
          },
        ]} />

        <section className="md-band md-band--flush">
          <div className="md-band__head">
            <div>
              <h2 className="md-band__title">Roles</h2>
              <p className="md-band__note">A role is what somebody is given; the two columns beside it are what it buys. Changing a role moves the review count in the sidebar, because both read the same table.</p>
            </div>
          </div>
          <div className="md-tablewrap">
            <Table>
              <TableHeader>
                <TableRow>
                  <TableHead>Person</TableHead>
                  <TableHead>Role</TableHead>
                  <TableHead className="md-drop-md">Approves sends</TableHead>
                  <TableHead className="md-drop-lg">Edits and submits</TableHead>
                </TableRow>
              </TableHeader>
              <TableBody>
                {data.members.map((member) => {
                  const row = rows.find((r) => r.id === member.id) || { teamRole: member.teamRole };
                  const isSelf = member.id === viewer.id;
                  const select = (
                    <span className="md-cell-control">
                      <Select
                        size="sm"
                        items={TEAM_ROLES}
                        value={row.teamRole}
                        disabled={isSelf}
                        aria-label={"Role for " + member.name}
                        onValueChange={(value) => set(member.id, value)}
                      />
                    </span>
                  );
                  return (
                    <TableRow key={member.id}>
                      <TableCell>
                        <span className="md-person">
                          <Avatar size={32} src={member.avatar} alt="" fallback={member.name.split(" ").map((w) => w[0]).join("")} />
                          <span className="md-person__text">
                            <span className="md-record__name">{member.name}{isSelf ? " (you)" : ""}</span>
                            <span className="md-record__meta">{member.invited ? member.email : member.role}</span>
                          </span>
                          {member.invited ? <Badge size="sm" variant="warning">Invitation sent</Badge> : null}
                        </span>
                      </TableCell>
                      <TableCell>
                        {isSelf ? <FloatingTip label="You cannot change your own role — ask another admin or the owner." side="bottom">{select}</FloatingTip> : select}
                      </TableCell>
                      <TableCell className="md-drop-md">
                        {member.invited
                          ? <span className="md-muted">Not until they accept</span>
                          : ROLE_CAN_APPROVE[row.teamRole] ? "Yes" : <span className="md-muted">No</span>}
                      </TableCell>
                      <TableCell className="md-drop-lg">
                        {ROLE_CAN_EDIT[row.teamRole] ? "Yes" : <span className="md-muted">Read only</span>}
                      </TableCell>
                    </TableRow>
                  );
                })}
              </TableBody>
            </Table>
          </div>
        </section>

        <FormBar
          dirty={dirty && !wouldStrand}
          label="Save roles"
          note={wouldStrand
            ? "At least one person has to be able to approve a send, or every broadcast would sit in review."
            : dirty
              ? "Nothing is applied until you save. After saving, " + approvers.length + (approvers.length === 1 ? " person" : " people") + " could approve a send."
              : approvers.length + " of " + data.members.length + " people can approve a send."}
          onCancel={() => setRows(initial)}
          onSave={() => onSave(rows)}
        />
      </>
    );
  }

  Object.assign(window, { WorkspaceSettingsScreen, TeamScreen });
})();
