'use client'

/**
 * TeamSettingsPage — shared composer for /settings/team across every app
 * in the monorepo (startsim-o7s).
 *
 * Wires:
 *   - useAuth (current user + logout)
 *   - useMembershipFromApi (company + currentTeam + isAdmin)
 *   - useInvitations (pending invitations)
 *   - api.teams.members / updateRole / removeMember (members table)
 *   - LeaveTeamDialog (calls api.teams.removeMember on the current user)
 *
 * Apps pass:
 *   - api: the @startsimpli/api client (structurally typed below)
 *   - centralAuthApp: app slug for buildCentralAuthUrl (e.g. 'vault')
 *   - classNames: optional per-slot Tailwind overrides
 *   - onLeftTeam: optional override; defaults to logout + central-auth bounce
 */

import * as React from 'react'
import {
  useAuth,
  useInvitations,
  useMembershipFromApi,
  buildCentralAuthUrl,
} from '@startsimpli/auth'
import { MembersTable } from '../MembersTable'
import { InviteMemberDialog } from '../InviteMemberDialog'
import { LeaveTeamDialog } from '../LeaveTeamDialog'
import type {
  MemberRow,
  TeamRole,
  InvitationLite,
} from '../types'
import {
  TEAM_SETTINGS_PAGE_DEFAULTS,
  type TeamSettingsPageClassNames,
} from './team-settings-page-default-class-names'
import type {
  TeamSettingsApi,
  ApiInvitation,
  ApiMember,
} from './types'

export interface TeamSettingsPageProps {
  /** The @startsimpli/api client. */
  api: TeamSettingsApi
  /** Central-auth app slug (e.g. 'vault', 'market', 'raise'). */
  centralAuthApp: string
  /** Per-slot className overrides. */
  classNames?: TeamSettingsPageClassNames
  /**
   * Optional override for the post-leave handler. Defaults to logout +
   * redirect to central auth. Tested-only override path; most apps don't
   * need to set it.
   */
  onLeftTeam?: () => void
  /**
   * Optional href used by the back link. Defaults to '/'. Apps can point at
   * their dashboard route ('/environments', '/dashboard', etc.).
   */
  backHref?: string
  /** Text shown for the back link. Defaults to '← Back'. */
  backLabel?: string
  /** Title shown in the header. Defaults to 'Team & members'. */
  title?: string
}

/** Human-friendly relative-ish expiry. Keeps the wire untouched. */
function formatExpiry(iso: string): string {
  try {
    const d = new Date(iso)
    return d.toLocaleDateString(undefined, { month: 'short', day: 'numeric' })
  } catch {
    return iso
  }
}

/** Render the backend's 400 "last owner" error in a friendly way. */
function friendlyRoleError(err: unknown): string {
  if (err instanceof Error && /owner/i.test(err.message)) {
    return 'A team must always have at least one owner.'
  }
  return err instanceof Error ? err.message : 'Could not update role.'
}

function toInvitationLite(i: ApiInvitation): InvitationLite {
  return {
    id: i.id,
    email: i.email,
    teamId: i.teamId,
    role: i.role,
    token: i.token,
    expiresAt: i.expiresAt,
    acceptedAt: i.acceptedAt,
    revokedAt: i.revokedAt,
    isExpired: i.isExpired,
    isAccepted: i.isAccepted,
  }
}

export function TeamSettingsPage({
  api,
  centralAuthApp,
  classNames,
  onLeftTeam,
  backHref = '/',
  backLabel = '← Back',
  title = 'Team & members',
}: TeamSettingsPageProps) {
  const cls = { ...TEAM_SETTINGS_PAGE_DEFAULTS, ...(classNames ?? {}) }
  const { user, logout } = useAuth()
  const membership = useMembershipFromApi(api)
  const { company, currentTeam, isAdmin, isLoading, error, refresh } = membership

  const teamId = currentTeam?.id
  const teamSlug = currentTeam?.slug ?? teamId

  const [members, setMembers] = React.useState<MemberRow[]>([])
  const [membersLoading, setMembersLoading] = React.useState(false)
  const [membersError, setMembersError] = React.useState<string>('')
  const [mutationError, setMutationError] = React.useState<string>('')

  const loadMembers = React.useCallback(async () => {
    if (!teamSlug) return
    setMembersLoading(true)
    setMembersError('')
    try {
      const rows: ApiMember[] = await api.teams.members(teamSlug)
      setMembers(
        rows.map((m) => ({
          id: m.id,
          userId: m.userId,
          teamId: m.teamId,
          role: m.role,
          joinedAt: m.joinedAt,
          user: m.user,
        })),
      )
    } catch (err) {
      setMembersError(err instanceof Error ? err.message : 'Could not load members')
    } finally {
      setMembersLoading(false)
    }
  }, [api, teamSlug])

  React.useEffect(() => {
    void loadMembers()
  }, [loadMembers])

  const invitations = useInvitations({
    fetchInvitations: async () => {
      if (!teamSlug) return []
      const res = await api.teamInvitations.list({ teamId: teamSlug })
      return res.results.map((i) => ({
        id: i.id,
        email: i.email,
        teamId: i.teamId,
        role: i.role,
        expiresAt: i.expiresAt,
        acceptedAt: i.acceptedAt,
        revokedAt: i.revokedAt,
        isExpired: i.isExpired,
        isAccepted: i.isAccepted,
        createdAt: i.createdAt,
      }))
    },
    revokeInvitation: async (id) => {
      await api.teamInvitations.revoke(id)
    },
    bulkInviteToTeam: async (slug, invites) => {
      const result = await api.teams.bulkInvite(slug, invites)
      return {
        invited: result.invited.map((i) => ({
          id: i.id,
          email: i.email,
          teamId: i.teamId,
          role: i.role,
          expiresAt: i.expiresAt,
          acceptedAt: i.acceptedAt,
          revokedAt: i.revokedAt,
          isExpired: i.isExpired,
          isAccepted: i.isAccepted,
          createdAt: i.createdAt,
        })),
        skipped: result.skipped,
      }
    },
    autoFetch: false,
  })

  React.useEffect(() => {
    if (teamSlug) void invitations.refresh()
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, [teamSlug])

  async function handleChangeRole(userId: string, role: TeamRole) {
    if (!teamSlug) return
    setMutationError('')
    const snapshot = members
    setMembers((prev) => prev.map((m) => (m.userId === userId ? { ...m, role } : m)))
    try {
      await api.teams.updateRole(teamSlug, userId, role)
    } catch (err) {
      setMembers(snapshot)
      setMutationError(friendlyRoleError(err))
    }
  }

  async function handleRemove(userId: string) {
    if (!teamSlug) return
    setMutationError('')
    const snapshot = members
    setMembers((prev) => prev.filter((m) => m.userId !== userId))
    try {
      await api.teams.removeMember(teamSlug, userId)
    } catch (err) {
      setMembers(snapshot)
      setMutationError(friendlyRoleError(err))
    }
  }

  async function handleLeave() {
    if (!teamSlug || !user) return
    await api.teams.removeMember(teamSlug, user.id)
  }

  function defaultOnLeftTeam() {
    void logout().finally(() => {
      if (typeof window !== 'undefined') {
        window.location.href = buildCentralAuthUrl('signin', {
          app: centralAuthApp,
          returnTo: `${window.location.origin}/`,
        })
      }
    })
  }

  // ----- Render -----------------------------------------------------------

  if (isLoading) {
    return <p className={cls.loadingText}>Loading team…</p>
  }

  if (error) {
    return (
      <div className={cls.section}>
        <p className={cls.errorText}>Could not load team membership.</p>
        <button
          type="button"
          onClick={() => void refresh()}
          className={cls.retryButton}
        >
          Retry
        </button>
      </div>
    )
  }

  if (!currentTeam) {
    return (
      <div className={cls.section}>
        <a href={backHref} className={cls.backLink}>
          {backLabel}
        </a>
        <h1 className={cls.title}>{title}</h1>
        <p className={cls.sectionBody}>
          You aren&apos;t a member of any team yet. Accept an invitation or ask
          an admin to add you.
        </p>
      </div>
    )
  }

  const handleInvited = () => {
    void invitations.refresh()
  }

  return (
    <div className={cls.root}>
      <div className={cls.header}>
        <a href={backHref} className={cls.backLink}>
          {backLabel}
        </a>
        <h1 className={cls.title}>{title}</h1>
        <p className={cls.subtitle}>
          {company ? `${company.name} · ` : ''}
          {currentTeam.name}
        </p>
      </div>

      {/* Members --------------------------------------------------------- */}
      <section className={cls.section}>
        <div className={cls.sectionHeader}>
          <h2 className={cls.sectionHeading}>Members</h2>
          {isAdmin && teamId && (
            <InviteMemberDialog
              teamId={teamId}
              triggerLabel="+ Invite"
              classNames={cls.inviteDialog}
              onSubmit={(input) =>
                api.teamInvitations
                  .create({
                    email: input.email,
                    teamId: input.teamId,
                    role: input.role,
                  })
                  .then(toInvitationLite)
              }
              onInvited={handleInvited}
            />
          )}
        </div>
        {mutationError && (
          <p className={cls.errorText} role="alert">
            {mutationError}
          </p>
        )}
        {membersError && (
          <div className="space-y-2">
            <p className={cls.errorText}>{membersError}</p>
            <button
              type="button"
              onClick={() => void loadMembers()}
              className={cls.retryButton}
            >
              Retry
            </button>
          </div>
        )}
        {membersLoading ? (
          <p className={cls.loadingText}>Loading members…</p>
        ) : (
          <MembersTable
            members={members}
            canManage={isAdmin}
            onChangeRole={handleChangeRole}
            onRemove={handleRemove}
            classNames={cls.membersTable}
          />
        )}
      </section>

      {/* Pending invitations --------------------------------------------- */}
      <section className={cls.section}>
        <h2 className={cls.sectionHeading}>Pending invitations</h2>
        {invitations.isLoading ? (
          <p className={cls.loadingText}>Loading invitations…</p>
        ) : invitations.error ? (
          <div className="space-y-2">
            <p className={cls.errorText}>Could not load invitations.</p>
            <button
              type="button"
              onClick={() => void invitations.refresh()}
              className={cls.retryButton}
            >
              Retry
            </button>
          </div>
        ) : invitations.pending.length === 0 ? (
          <p className={cls.emptyText}>No pending invitations.</p>
        ) : (
          <div className={cls.invitationsTableWrapper}>
            <table className={cls.invitationsTable}>
              <thead className={cls.invitationsThead}>
                <tr>
                  <th className={cls.invitationsTh}>Email</th>
                  <th className={cls.invitationsTh}>Role</th>
                  <th className={cls.invitationsTh}>Expires</th>
                  <th className={`${cls.invitationsTh} text-right`}>Actions</th>
                </tr>
              </thead>
              <tbody className={cls.invitationsTbody}>
                {invitations.pending.map((inv) => (
                  <tr key={inv.id}>
                    <td className={cls.invitationsEmailCell}>{inv.email}</td>
                    <td className={cls.invitationsRoleCell}>
                      <span className={cls.invitationsRoleBadge}>{inv.role}</span>
                    </td>
                    <td className={cls.invitationsExpiryCell}>
                      {formatExpiry(inv.expiresAt)}
                    </td>
                    <td className={cls.invitationsActionsCell}>
                      {isAdmin && (
                        <button
                          type="button"
                          onClick={() => void invitations.revoke(inv.id)}
                          className={cls.invitationsRevokeButton}
                        >
                          Revoke
                        </button>
                      )}
                    </td>
                  </tr>
                ))}
              </tbody>
            </table>
          </div>
        )}
      </section>

      {/* Leave team ------------------------------------------------------- */}
      <section className={cls.dangerDivider}>
        <h2 className={cls.sectionHeading}>Danger zone</h2>
        <p className={cls.sectionBody}>
          Leave this team. You&apos;ll need a fresh invitation to rejoin.
        </p>
        <LeaveTeamDialog
          team={{
            id: currentTeam.id,
            slug: currentTeam.slug,
            name: currentTeam.name,
            companyId: currentTeam.companyId,
          }}
          onSubmit={handleLeave}
          onLeft={onLeftTeam ?? defaultOnLeftTeam}
          classNames={cls.leaveDialog}
        />
      </section>
    </div>
  )
}
