import React, { useEffect, useMemo, useState } from 'react';

import { Button } from '@renderer/components/ui/button';
import { Label } from '@renderer/components/ui/label';
import { CUSTOM_ROLE, NO_ROLE, PRESET_ROLES } from '@renderer/constants/teamRoles';
import { normalizeOptionalTeamProviderId } from '@shared/utils/teamProvider';
import { Plus } from 'lucide-react';

import { MembersJsonEditor } from '../dialogs/MembersJsonEditor';

import { MemberDraftRow } from './MemberDraftRow';
import { getNextSuggestedMemberName } from './memberNameSets';
import {
  buildMemberDraftColorMap,
  buildMemberDraftSuggestions,
  createMemberDraft,
  getMemberDraftRole,
  getWorkflowForExport,
} from './membersEditorUtils';

import type { MemberDraft } from './membersEditorTypes';
import type { InlineChip } from '@renderer/types/inlineChip';
import type { MentionSuggestion } from '@renderer/types/mention';
import type { EffortLevel, TeamProviderId } from '@shared/types';

function membersToJsonText(drafts: MemberDraft[]): string {
  const arr = drafts
    .filter((d) => d.name.trim())
    .map((d) => {
      const role = getMemberDraftRole(d);
      const obj: Record<string, string> = { name: d.name.trim() };
      if (role) obj.role = role;
      const workflow = getWorkflowForExport(d);
      if (workflow) obj.workflow = workflow;
      if (d.providerId) obj.providerId = d.providerId;
      if (d.model?.trim()) obj.model = d.model.trim();
      if (d.effort) obj.effort = d.effort;
      return obj;
    });
  return JSON.stringify(arr, null, 2);
}

function parseJsonToDrafts(text: string): MemberDraft[] {
  const arr: unknown = JSON.parse(text);
  if (!Array.isArray(arr)) return [];
  return (arr as Record<string, unknown>[]).map((item) => {
    const name = typeof item.name === 'string' ? item.name : '';
    const role = typeof item.role === 'string' ? item.role.trim() : '';
    const workflow = typeof item.workflow === 'string' ? item.workflow.trim() : '';
    const providerId = normalizeOptionalTeamProviderId(item.providerId);
    const model = typeof item.model === 'string' ? item.model.trim() : '';
    const effort: EffortLevel | undefined =
      item.effort === 'low' || item.effort === 'medium' || item.effort === 'high'
        ? item.effort
        : undefined;
    const presetRoles: readonly string[] = PRESET_ROLES;
    const isPreset = presetRoles.includes(role);
    return createMemberDraft({
      name,
      roleSelection: role ? (isPreset ? role : CUSTOM_ROLE) : '',
      customRole: role && !isPreset ? role : '',
      workflow: workflow || undefined,
      providerId,
      model,
      effort,
    });
  });
}

export interface MembersEditorSectionProps {
  members: MemberDraft[];
  onChange: (members: MemberDraft[]) => void;
  fieldError?: string;
  validateMemberName?: (name: string) => string | null;
  showWorkflow?: boolean;
  showJsonEditor?: boolean;
  /** Prefix for draft persistence keys (e.g. 'createTeam' or 'editTeam:team-alpha') */
  draftKeyPrefix?: string;
  /** Project path for @file mentions in workflow */
  projectPath?: string | null;
  /** Task suggestions for #task references in workflow */
  taskSuggestions?: MentionSuggestion[];
  /** Team suggestions for @@team mentions in workflow */
  teamSuggestions?: MentionSuggestion[];
  /** Extra content rendered right below the "Members" label row */
  headerExtra?: React.ReactNode;
  /** When true, hides member rows and action buttons (label + headerExtra still visible) */
  hideContent?: boolean;
  /** Existing team members — used to reserve their colors so drafts get the next available ones */
  existingMembers?: readonly { name: string; color?: string; removedAt?: number | string | null }[];
  /** Default provider to use for newly added member rows. */
  defaultProviderId?: TeamProviderId;
  /** When true, provider/model controls stay read-only for existing rows. */
  lockProviderModel?: boolean;
  inheritedProviderId?: TeamProviderId;
  inheritedModel?: string;
  inheritedEffort?: EffortLevel;
  inheritModelSettingsByDefault?: boolean;
  forceInheritedModelSettings?: boolean;
  modelLockReason?: string;
  softDeleteMembers?: boolean;
  memberWarningById?: Record<string, string | null | undefined>;
  disableGeminiOption?: boolean;
}

export const MembersEditorSection = ({
  members,
  onChange,
  fieldError,
  validateMemberName,
  showWorkflow = false,
  showJsonEditor = true,
  draftKeyPrefix,
  projectPath,
  taskSuggestions,
  teamSuggestions,
  headerExtra,
  hideContent = false,
  existingMembers,
  defaultProviderId = 'anthropic',
  lockProviderModel = false,
  inheritedProviderId,
  inheritedModel,
  inheritedEffort,
  inheritModelSettingsByDefault = false,
  forceInheritedModelSettings = false,
  modelLockReason,
  softDeleteMembers = false,
  memberWarningById,
  disableGeminiOption = false,
}: MembersEditorSectionProps): React.JSX.Element => {
  const [jsonEditorOpen, setJsonEditorOpen] = useState(false);
  const [jsonText, setJsonText] = useState('');
  const [jsonError, setJsonError] = useState<string | null>(null);

  const toggleJsonEditor = (): void => {
    if (!jsonEditorOpen) {
      setJsonText(membersToJsonText(members));
      setJsonError(null);
    }
    setJsonEditorOpen((prev) => !prev);
  };

  useEffect(() => {
    if (!jsonEditorOpen || jsonError !== null) return;
    queueMicrotask(() => setJsonText(membersToJsonText(members)));
  }, [members, jsonEditorOpen, jsonError]);

  const handleJsonChange = (text: string): void => {
    setJsonText(text);
    try {
      const drafts = parseJsonToDrafts(text);
      onChange(drafts);
      setJsonError(null);
    } catch (e) {
      setJsonError(e instanceof Error ? e.message : 'Invalid JSON');
    }
  };

  const updateMemberName = (memberId: string, name: string): void => {
    onChange(members.map((c) => (c.id === memberId ? { ...c, name } : c)));
  };

  const updateMemberRole = (memberId: string, roleSelection: string): void => {
    const resolvedRole = roleSelection === NO_ROLE ? '' : roleSelection;
    onChange(
      members.map((c) =>
        c.id === memberId
          ? {
              ...c,
              roleSelection: resolvedRole,
              customRole: resolvedRole === CUSTOM_ROLE ? c.customRole : '',
            }
          : c
      )
    );
  };

  const updateMemberCustomRole = (memberId: string, customRole: string): void => {
    onChange(members.map((c) => (c.id === memberId ? { ...c, customRole } : c)));
  };

  const updateMemberWorkflow = (memberId: string, workflow: string): void => {
    onChange(members.map((c) => (c.id === memberId ? { ...c, workflow } : c)));
  };

  const updateMemberWorkflowChips = (memberId: string, workflowChips: InlineChip[]): void => {
    onChange(members.map((c) => (c.id === memberId ? { ...c, workflowChips } : c)));
  };

  const updateMemberProvider = (memberId: string, providerId: TeamProviderId): void => {
    onChange(
      members.map((c) =>
        c.id === memberId
          ? {
              ...c,
              providerId,
              model: c.providerId === providerId ? c.model : '',
            }
          : c
      )
    );
  };

  const updateMemberModel = (memberId: string, model: string): void => {
    onChange(members.map((c) => (c.id === memberId ? { ...c, model } : c)));
  };

  const updateMemberEffort = (memberId: string, effort: string): void => {
    onChange(
      members.map((c) =>
        c.id === memberId
          ? {
              ...c,
              effort:
                effort === 'low' || effort === 'medium' || effort === 'high' ? effort : undefined,
            }
          : c
      )
    );
  };

  const removeMember = (memberId: string): void => {
    if (!softDeleteMembers) {
      onChange(members.filter((c) => c.id !== memberId));
      return;
    }
    onChange(
      members.map((member) =>
        member.id === memberId ? { ...member, removedAt: member.removedAt ?? Date.now() } : member
      )
    );
  };

  const restoreMember = (memberId: string): void => {
    onChange(
      members.map((member) => (member.id === memberId ? { ...member, removedAt: null } : member))
    );
  };

  const addMember = (): void => {
    const suggestedName = getNextSuggestedMemberName(members.map((member) => member.name));
    onChange([
      ...members,
      createMemberDraft(
        inheritModelSettingsByDefault
          ? { name: suggestedName }
          : { name: suggestedName, providerId: defaultProviderId }
      ),
    ]);
  };

  const activeMembers = members.filter((member) => !member.removedAt);
  const removedMembers = members.filter((member) => member.removedAt);
  const names = activeMembers.map((m) => m.name.trim().toLowerCase()).filter(Boolean);
  const hasDuplicates = new Set(names).size !== names.length;
  const memberColorMap = useMemo(
    () => buildMemberDraftColorMap(members, existingMembers),
    [members, existingMembers]
  );

  const mentionSuggestions = useMemo(
    () => buildMemberDraftSuggestions(members, memberColorMap),
    [members, memberColorMap]
  );

  return (
    <div className="space-y-1.5">
      <div className="flex items-center justify-between">
        <Label>Members</Label>
        {!hideContent && (
          <div className="flex gap-2">
            <Button variant="outline" size="sm" className="gap-1.5" onClick={addMember}>
              <Plus className="size-3.5" />
              Add member
            </Button>
            {showJsonEditor && !jsonEditorOpen ? (
              <Button variant="ghost" size="sm" onClick={toggleJsonEditor}>
                Edit as JSON
              </Button>
            ) : null}
          </div>
        )}
      </div>
      {headerExtra}
      {!hideContent && (
        <>
          <div className="space-y-2">
            {activeMembers.map((member, index) => (
              <MemberDraftRow
                key={member.id}
                member={member}
                index={index}
                resolvedColor={memberColorMap.get(member.name.trim())}
                nameError={validateMemberName?.(member.name) ?? null}
                onNameChange={updateMemberName}
                onRoleChange={updateMemberRole}
                onCustomRoleChange={updateMemberCustomRole}
                onRemove={removeMember}
                showWorkflow={showWorkflow}
                onWorkflowChange={showWorkflow ? updateMemberWorkflow : undefined}
                onWorkflowChipsChange={showWorkflow ? updateMemberWorkflowChips : undefined}
                onProviderChange={updateMemberProvider}
                onModelChange={updateMemberModel}
                onEffortChange={updateMemberEffort}
                inheritedProviderId={inheritedProviderId}
                inheritedModel={inheritedModel}
                inheritedEffort={inheritedEffort}
                forceInheritedModelSettings={forceInheritedModelSettings}
                draftKeyPrefix={draftKeyPrefix}
                projectPath={projectPath}
                mentionSuggestions={mentionSuggestions}
                taskSuggestions={taskSuggestions}
                teamSuggestions={teamSuggestions}
                lockProviderModel={lockProviderModel}
                modelLockReason={modelLockReason}
                warningText={memberWarningById?.[member.id] ?? null}
                disableGeminiOption={disableGeminiOption}
              />
            ))}
            {softDeleteMembers && removedMembers.length > 0 ? (
              <div className="pt-2">
                <div className="mb-2 text-[10px] text-[var(--color-text-muted)]">
                  Removed ({removedMembers.length})
                </div>
                <div className="space-y-2">
                  {removedMembers.map((member, index) => (
                    <MemberDraftRow
                      key={member.id}
                      member={member}
                      index={activeMembers.length + index}
                      resolvedColor={memberColorMap.get(member.name.trim())}
                      nameError={null}
                      onNameChange={updateMemberName}
                      onRoleChange={updateMemberRole}
                      onCustomRoleChange={updateMemberCustomRole}
                      onRemove={removeMember}
                      onRestore={restoreMember}
                      showWorkflow={showWorkflow}
                      onWorkflowChange={showWorkflow ? updateMemberWorkflow : undefined}
                      onWorkflowChipsChange={showWorkflow ? updateMemberWorkflowChips : undefined}
                      onProviderChange={updateMemberProvider}
                      onModelChange={updateMemberModel}
                      onEffortChange={updateMemberEffort}
                      inheritedProviderId={inheritedProviderId}
                      inheritedModel={inheritedModel}
                      inheritedEffort={inheritedEffort}
                      forceInheritedModelSettings={forceInheritedModelSettings}
                      draftKeyPrefix={draftKeyPrefix}
                      projectPath={projectPath}
                      mentionSuggestions={mentionSuggestions}
                      taskSuggestions={taskSuggestions}
                      teamSuggestions={teamSuggestions}
                      lockProviderModel
                      modelLockReason="Removed members are kept for soft delete history. Restore them to edit settings."
                      isRemoved
                      warningText={null}
                      disableGeminiOption={disableGeminiOption}
                    />
                  ))}
                </div>
              </div>
            ) : null}
            {jsonEditorOpen && showJsonEditor ? (
              <MembersJsonEditor
                value={jsonText}
                onChange={handleJsonChange}
                error={jsonError}
                onClose={toggleJsonEditor}
              />
            ) : null}
          </div>
          {hasDuplicates ? (
            <p className="text-[11px]" style={{ color: 'var(--field-error-text)' }}>
              Member names must be unique
            </p>
          ) : fieldError ? (
            <p className="text-[11px]" style={{ color: 'var(--field-error-text)' }}>
              {fieldError}
            </p>
          ) : null}
        </>
      )}
    </div>
  );
};

export type { MemberDraft } from './membersEditorTypes';
export {
  buildMemberDraftColorMap,
  buildMemberDraftSuggestions,
  buildMembersFromDrafts,
  clearMemberModelOverrides,
  createMemberDraft,
  createMemberDraftsFromInputs,
  getMemberDraftRole,
  normalizeMemberDraftForProviderMode,
  normalizeProviderForMode,
  validateMemberNameInline,
} from './membersEditorUtils';
