/* ---------------------------------------------------------------------------
 * People (users) resource — replaces the old Participants tab.
 *
 * Single resource for every user, regardless of role. The filter chips swap
 * the visible columns (council shows member_number + focus_tags; pilots/team
 * show role + last_seen_at). The edit panel's CAB-specific fields render
 * only when the user is in role=cab.
 *
 * Creation is intentionally absent — users come in through invites, not
 * direct admin creation. The "+ New" button is suppressed automatically
 * because ops.create is undefined.
 * ------------------------------------------------------------------------- */

import {
  getAllUsersPublic,
  getUserPublicById,
  updateUserAdminFields,
  updateUserEmail,
  updateUserPassword,
  updateUserProfile,
  updateUserRole,
  deactivateUser,
  type Role,
  type UserPublic,
} from '../../lib/db';
import { generateTempPassword, hashPassword } from '../../lib/auth';
import { parseFocusTags, readFocusTags } from '../../lib/format';
import type { Resource } from '../resource-types';

const ROLE_LABEL: Record<Role, string> = {
  pilot: 'Pilot',
  cab: 'Council',
  fenja: 'Fenja team',
};

const ROLE_PILL_CLASS: Record<Role, string> = {
  pilot: 'pill-pilot',
  cab: 'pill-cab',
  fenja: 'pill-fenja',
};

export const usersResource: Resource<UserPublic> = {
  key: 'users',
  label: 'People',
  pluralLabel: 'People',
  singularLabel: 'Person',
  groupKey: 'council',
  description: 'Everyone with an account on the portal — pilots, council, and team.',
  publicRoutePattern: (item) => (item.slug ? `/members/${item.slug}` : null),

  list: {
    queryFn: () => getAllUsersPublic(),

    // Default columns shown under "Council" (the default filter): the CAB-
    // specific identity columns.
    columns: [
      {
        key: 'name',
        label: 'Name',
        primary: true,
        width: '2fr',
        render: (item) => ({
          title: item.name,
          subtitle: item.email,
        }),
      },
      {
        key: 'member_number',
        label: 'Member #',
        kind: 'number',
        width: '100px',
        value: (item) => item.member_number,
      },
      {
        key: 'organisation',
        label: 'Organisation',
        width: '1.5fr',
        render: (item) => ({ title: item.organisation || '—' }),
      },
      {
        key: 'focus_tags',
        label: 'Focus',
        kind: 'tag-list',
        width: '1.5fr',
        value: (item) => readFocusTags(item.focus_tags),
      },
    ],

    // Pilots / Team / All show role + organisation + last seen instead.
    columnsByFilter: {
      pilots: [
        {
          key: 'name',
          label: 'Name',
          primary: true,
          width: '2fr',
          render: (item) => ({ title: item.name, subtitle: item.email }),
        },
        {
          key: 'role',
          label: 'Role',
          kind: 'pill',
          width: '120px',
          pillVariants: {
            pilot: { label: 'Pilot', class: 'pill-pilot' },
            cab: { label: 'Council', class: 'pill-cab' },
            fenja: { label: 'Fenja team', class: 'pill-fenja' },
          },
        },
        {
          key: 'organisation',
          label: 'Organisation',
          width: '1.5fr',
          render: (item) => ({ title: item.organisation || '—' }),
        },
        {
          key: 'last_seen_at',
          label: 'Last seen',
          kind: 'relative-date',
          width: '120px',
          emptyFallback: 'never',
        },
      ],
      team: [
        {
          key: 'name',
          label: 'Name',
          primary: true,
          width: '2fr',
          render: (item) => ({ title: item.name, subtitle: item.email }),
        },
        {
          key: 'role',
          label: 'Role',
          kind: 'pill',
          width: '120px',
          pillVariants: {
            pilot: { label: 'Pilot', class: 'pill-pilot' },
            cab: { label: 'Council', class: 'pill-cab' },
            fenja: { label: 'Fenja team', class: 'pill-fenja' },
          },
        },
        {
          key: 'organisation',
          label: 'Organisation',
          width: '1.5fr',
          render: (item) => ({ title: item.organisation || '—' }),
        },
        {
          key: 'last_seen_at',
          label: 'Last seen',
          kind: 'relative-date',
          width: '120px',
          emptyFallback: 'never',
        },
      ],
      all: [
        {
          key: 'name',
          label: 'Name',
          primary: true,
          width: '2fr',
          render: (item) => ({ title: item.name, subtitle: item.email }),
        },
        {
          key: 'role',
          label: 'Role',
          kind: 'pill',
          width: '120px',
          pillVariants: {
            pilot: { label: 'Pilot', class: 'pill-pilot' },
            cab: { label: 'Council', class: 'pill-cab' },
            fenja: { label: 'Fenja team', class: 'pill-fenja' },
          },
        },
        {
          key: 'organisation',
          label: 'Organisation',
          width: '1.5fr',
          render: (item) => ({ title: item.organisation || '—' }),
        },
        {
          key: 'last_seen_at',
          label: 'Last seen',
          kind: 'relative-date',
          width: '120px',
          emptyFallback: 'never',
        },
      ],
    },

    filters: [
      { key: 'council', label: 'Council', predicate: (i) => i.role === 'cab', isDefault: true },
      { key: 'pilots', label: 'Pilots', predicate: (i) => i.role === 'pilot' },
      { key: 'team', label: 'Team', predicate: (i) => i.role === 'fenja' },
      { key: 'all', label: 'All', predicate: () => true },
    ],
    search: {
      placeholder: 'Search by name, email, organisation…',
      fields: ['name', 'email', 'organisation'],
    },
    defaultSort: { key: 'name', direction: 'asc' },
    pageSize: 50,
  },

  form: {
    fields: [
      // ── Always visible ───────────────────────────────────────────────
      {
        key: 'role',
        label: 'Role',
        kind: 'select',
        required: true,
        options: [
          { value: 'pilot', label: 'Pilot' },
          { value: 'cab', label: 'Council' },
          { value: 'fenja', label: 'Fenja team' },
        ],
        helperText:
          'Changing the role has real access consequences. Setting to Council also allocates a member number.',
      },
      { key: 'name', label: 'Name', kind: 'text', required: true, maxLength: 120 },
      {
        key: 'email',
        label: 'Email',
        kind: 'text',
        required: true,
        maxLength: 200,
        pattern: /^[^\s@]+@[^\s@]+\.[^\s@]+$/,
        helperText: 'The member’s login identity. Normalised to lowercase on save; must be unique.',
      },
      { key: 'organisation', label: 'Organisation', kind: 'text', readOnly: true,
        helperText: 'Set at sign-up; editing is not yet supported.' },
      { key: 'bio', label: 'Bio', kind: 'textarea', rows: 4 },

      // ── CAB-only ────────────────────────────────────────────────────
      {
        key: 'title',
        label: 'Title',
        kind: 'text',
        maxLength: 120,
        visibleWhen: (ctx) => ctx.formValues.role === 'cab',
      },
      {
        key: 'pull_quote',
        label: 'Pull quote',
        kind: 'textarea',
        rows: 3,
        maxLength: 240,
        helperText: 'Shown on the member profile page. Two sentences max.',
        visibleWhen: (ctx) => ctx.formValues.role === 'cab',
      },
      {
        key: 'focus_tags_text',
        label: 'Focus tags',
        kind: 'text',
        maxLength: 80,
        helperText:
          'Comma-separated. Up to 3 tags, 24 chars each. Normalised on save.',
        visibleWhen: (ctx) => ctx.formValues.role === 'cab',
      },
      {
        key: 'cab_joined_date',
        label: 'Council joined',
        kind: 'readonly',
        visibleWhen: (ctx) => ctx.formValues.role === 'cab',
        render: (value) => (value ? String(value) : '—'),
      },
      {
        key: 'member_number',
        label: 'Member number',
        kind: 'readonly',
        visibleWhen: (ctx) => ctx.formValues.role === 'cab',
        render: (value) => (value ? `#${value}` : 'pending'),
      },
    ],
  },

  ops: {
    getById: (id) => {
      const u = getUserPublicById(id);
      if (!u) return null;
      // Surface focus_tags as plaintext for the editor.
      return {
        ...u,
        focus_tags_text: readFocusTags(u.focus_tags).join(', '),
      } as unknown as UserPublic;
    },

    // No ops.create — users come in via invites.

    update: (id, data) => {
      const current = getUserPublicById(id);
      if (!current) throw new Error(`User ${id} not found`);

      // Email (login identity) — only written when changed. Throws on a
      // collision, which the save handler surfaces as a form error.
      const newEmail = String(data.email ?? '').trim().toLowerCase();
      if (newEmail && newEmail !== current.email) {
        updateUserEmail(id, newEmail);
      }

      // Profile fields (name + bio).
      const newName = String(data.name ?? current.name);
      const newBio = String(data.bio ?? current.bio ?? '');
      updateUserProfile(id, newName, newBio);

      // Role transition — runs after profile update so member_number can be
      // allocated against an up-to-date user row.
      const newRole = data.role as Role;
      if (newRole && newRole !== current.role) {
        updateUserRole(id, newRole);
      }

      // CAB-specific admin fields. Only applied when the user is CAB after
      // the role update; otherwise the form fields aren't visible.
      const isCab = (newRole ?? current.role) === 'cab';
      if (isCab) {
        const tagsRaw = String(data.focus_tags_text ?? '');
        updateUserAdminFields(id, {
          title: ((data.title as string) ?? '').trim() || null,
          pull_quote: ((data.pull_quote as string) ?? '').trim() || null,
          focus_tags: parseFocusTags(tagsRaw),
        });
      }
    },

    delete: (id) => deactivateUser(id),
  },

  actions: [
    {
      key: 'reset-password',
      label: 'Reset password',
      confirmText:
        'Generate a new temporary password for this user? Their current password stops working immediately. You will get a password to send them.',
      handler: (id) => {
        const temp = generateTempPassword();
        updateUserPassword(id, hashPassword(temp));
        return { kind: 'temp-password', password: temp };
      },
    },
  ],

  notifyCount: {
    // CAB members without focus tags read as half-finished profiles —
    // surface them as something to attend to.
    count: (items) =>
      items.filter(
        (u) => u.role === 'cab' && readFocusTags(u.focus_tags).length === 0,
      ).length,
  },
};

// Keep the role label map exported for any callers that want display copy.
export { ROLE_LABEL, ROLE_PILL_CLASS };
