import { useCallback, useEffect, useMemo, useState } from 'react';
import { WizardStep } from './wizard-step';
import { TeamRightPane, type TeamMemberSummary } from './wizard-right-panes';
import {
    EmployeeCreateForm,
    emptyEmployeeCreateFormValues,
    generateTempPassword,
    type EmployeeCreateFormValues,
    type RoleOption,
} from '@/components/forms/employee-create-form';
import { Button } from '@/components/base/buttons/button';
import { apiClient } from '@/lib/api-client';
import { notify } from '@/lib/toast';
import { useAuth } from '@/providers/auth-provider';
import type { WizardStepComponentProps } from './wizard-step-types';

// Team step (post-rework) — creates workspace members directly from
// the portal via the sidecar's /api/team/members endpoint. The admin
// enters name + email + temp password + role. SIP seat assignment is
// NOT done here — it lives exclusively in the Telephony wizard step
// so admins manage one thing in one place.
//
// Edit mode: clicking the pencil icon on an employee row in the right
// pane loads that member back into the form (name + role only — email,
// password and SIP seat are not editable here). Save in edit mode
// fires PUT /api/team/members/:id instead of POST.
//
// Email invitations are NOT used anywhere in this flow. The admin is
// expected to share the temp password with the employee directly.
// Recently-created employees keep their plaintext password in
// component state so the right pane's copy icon can paste a
// shareable credentials block to the clipboard. Page reload clears
// that state — only employees created in the current session show
// the copy icon. Older members get only the edit icon.

// In-memory record of an employee the admin just created in this
// session. Holds the plaintext temp password so the copy-icon flow
// works without ever sending the password back from the server.
type CreatedMemberRecord = {
    id: string;
    userEmail: string;
    firstName: string;
    lastName: string;
    roleId: string;
    tempPassword: string;
};

type RoleRow = {
    id: string;
    label: string;
    description: string | null;
    canBeAssignedToUsers: boolean;
};

type AgentRow = {
    id: string;
    name: string | null;
    sipExtension: string | null;
    ozonetelAgentId: string | null;
    workspaceMemberId: string | null;
    workspaceMember: {
        id: string;
        name: { firstName: string | null; lastName: string | null } | null;
        userEmail: string;
    } | null;
};

type WorkspaceMemberRow = {
    id: string;
    userEmail: string;
    name: { firstName: string | null; lastName: string | null } | null;
    // Platform returns `null` (not an empty array) for members with no
    // role assigned — touching `.roles[0]` directly throws. Always
    // optional-chain reads.
    roles: { id: string; label: string }[] | null;
};

const AI_EMAIL_SUFFIX = '@ai.fortytwo.local';

// Build the credentials block that gets copied to the clipboard. Two
// lines (login url + email) plus the temp password — formatted so
// the admin can paste it straight into WhatsApp / SMS. Login URL is
// derived from the current browser origin since the wizard is always
// loaded from the workspace's own URL (or Vite dev), so this matches
// what the employee will use.
const buildCredentialsBlock = (email: string, tempPassword: string): string => {
    const origin = typeof window !== 'undefined' ? window.location.origin : '';
    return `Login: ${origin}/login\nEmail: ${email}\nTemporary password: ${tempPassword}`;
};

export const WizardStepTeam = (props: WizardStepComponentProps) => {
    const { user } = useAuth();
    const currentUserEmail = user?.email ?? null;

    // Initialise the form with a fresh temp password so the admin
    // doesn't have to click "regenerate" before saving the very first
    // employee.
    const [values, setValues] = useState<EmployeeCreateFormValues>(() => ({
        ...emptyEmployeeCreateFormValues,
        password: generateTempPassword(),
    }));
    const [editingMemberId, setEditingMemberId] = useState<string | null>(null);
    const [roles, setRoles] = useState<RoleOption[]>([]);
    // Agents are still fetched (even though we don't show a SIP seat
    // picker here) because the right-pane summary needs each member's
    // current SIP extension to show the green badge.
    const [agents, setAgents] = useState<AgentRow[]>([]);
    const [members, setMembers] = useState<WorkspaceMemberRow[]>([]);
    const [createdMembers, setCreatedMembers] = useState<CreatedMemberRecord[]>([]);
    const [saving, setSaving] = useState(false);
    const [loading, setLoading] = useState(true);

    const isEditing = editingMemberId !== null;

    const fetchRolesAndAgents = useCallback(async () => {
        try {
            const data = await apiClient.graphql<{
                getRoles: RoleRow[];
                agents: { edges: { node: AgentRow }[] };
                workspaceMembers: { edges: { node: WorkspaceMemberRow }[] };
            }>(
                `{
                    getRoles { id label description canBeAssignedToUsers }
                    agents(first: 100) {
                        edges { node {
                            id name sipExtension ozonetelAgentId workspaceMemberId
                            workspaceMember { id name { firstName lastName } userEmail }
                        } }
                    }
                    workspaceMembers(first: 200) {
                        edges { node {
                            id userEmail name { firstName lastName }
                            roles { id label }
                        } }
                    }
                }`,
                undefined,
                { silent: true },
            );
            const assignable = data.getRoles.filter((r) => r.canBeAssignedToUsers);
            setRoles(
                assignable.map((r) => ({
                    id: r.id,
                    label: r.label,
                    supportingText: r.description ?? undefined,
                })),
            );
            setAgents(data.agents.edges.map((e) => e.node));
            setMembers(
                data.workspaceMembers.edges
                    .map((e) => e.node)
                    .filter((m) => !m.userEmail.endsWith(AI_EMAIL_SUFFIX)),
            );
        } catch (err) {
            console.error('[wizard/team] fetch roles/agents failed', err);
        } finally {
            setLoading(false);
        }
    }, []);

    useEffect(() => {
        fetchRolesAndAgents();
    }, [fetchRolesAndAgents]);

    // Reset form back to a fresh "create" state with a new auto-gen
    // password. Used after both create-success and edit-cancel.
    const resetForm = () => {
        setEditingMemberId(null);
        setValues({
            ...emptyEmployeeCreateFormValues,
            password: generateTempPassword(),
        });
    };

    const handleSaveCreate = async () => {
        const firstName = values.firstName.trim();
        const email = values.email.trim();
        if (!firstName) {
            notify.error('First name is required');
            return;
        }
        if (!email) {
            notify.error('Email is required');
            return;
        }
        if (!values.password) {
            notify.error('Temporary password is required');
            return;
        }
        if (!values.roleId) {
            notify.error('Pick a role');
            return;
        }

        setSaving(true);
        try {
            const created = await apiClient.post<{
                id: string;
                userEmail: string;
                firstName: string;
                lastName: string;
                roleId: string;
            }>('/api/team/members', {
                firstName,
                lastName: values.lastName.trim(),
                email,
                password: values.password,
                roleId: values.roleId,
            });

            // Stash the plaintext temp password alongside the created
            // member so the copy-icon can build a credentials block
            // later. The password is NOT sent back from the server —
            // we hold the only copy in this component's memory.
            setCreatedMembers((prev) => [
                ...prev,
                { ...created, tempPassword: values.password },
            ]);
            notify.success(
                'Employee created',
                `${firstName} ${values.lastName.trim()}`.trim() || email,
            );
            await fetchRolesAndAgents();
            resetForm();
            if (!props.isCompleted) {
                await props.onComplete('team');
            }
        } catch (err) {
            console.error('[wizard/team] create failed', err);
        } finally {
            setSaving(false);
        }
    };

    const handleSaveUpdate = async () => {
        if (!editingMemberId) return;
        const firstName = values.firstName.trim();
        if (!firstName) {
            notify.error('First name is required');
            return;
        }
        if (!values.roleId) {
            notify.error('Pick a role');
            return;
        }
        setSaving(true);
        try {
            await apiClient.put(`/api/team/members/${editingMemberId}`, {
                firstName,
                lastName: values.lastName.trim(),
                roleId: values.roleId,
            });
            notify.success(
                'Employee updated',
                `${firstName} ${values.lastName.trim()}`.trim() || values.email,
            );
            await fetchRolesAndAgents();
            resetForm();
        } catch (err) {
            console.error('[wizard/team] update failed', err);
        } finally {
            setSaving(false);
        }
    };

    const handleSave = isEditing ? handleSaveUpdate : handleSaveCreate;

    // Right-pane edit handler — populate the form with the picked
    // member's data and switch into edit mode. Email is preserved as
    // the row's email (read-only in edit mode); password is cleared
    // since the form hides the field anyway.
    const handleEditMember = (memberId: string) => {
        const member = members.find((m) => m.id === memberId);
        if (!member) return;
        const firstRole = member.roles?.[0] ?? null;
        setEditingMemberId(memberId);
        setValues({
            firstName: member.name?.firstName ?? '',
            lastName: member.name?.lastName ?? '',
            email: member.userEmail,
            password: '',
            roleId: firstRole?.id ?? '',
        });
    };

    // Right-pane copy handler — build the shareable credentials block
    // and put it on the clipboard. Only fires for members in the
    // createdMembers in-memory map; rows without a known temp password
    // don't show the icon at all.
    const handleCopyCredentials = async (memberId: string) => {
        const member = members.find((m) => m.id === memberId);
        if (!member) return;

        // Three-tier fallback:
        //   1. In-browser memory (createdMembers state) — populated when
        //      the admin created this employee in the current session,
        //      survives until refresh. Fastest path, no network call.
        //   2. Sidecar Redis cache via GET /api/team/members/:id/temp-password
        //      — populated for any member created via this endpoint
        //      within the last 24h, survives reloads.
        //   3. Cache miss → tell the admin the password is no longer
        //      recoverable and direct them to the platform reset flow.
        const fromMemory =
            createdMembers.find(
                (c) => c.userEmail.toLowerCase() === member.userEmail.toLowerCase(),
            ) ?? createdMembers.find((c) => c.id === memberId);
        let tempPassword = fromMemory?.tempPassword ?? null;

        if (!tempPassword) {
            try {
                const res = await apiClient.get<{ password: string | null }>(
                    `/api/team/members/${memberId}/temp-password`,
                    { silent: true },
                );
                tempPassword = res.password;
            } catch (err) {
                console.error('[wizard/team] temp-password fetch failed', err);
            }
        }

        if (!tempPassword) {
            notify.error(
                'Password unavailable',
                'The temp password expired (>24h). Reset the password from settings to mint a new one.',
            );
            return;
        }

        const block = buildCredentialsBlock(member.userEmail, tempPassword);
        try {
            await navigator.clipboard.writeText(block);
            notify.success('Copied', 'Credentials copied to clipboard');
        } catch (err) {
            console.error('[wizard/team] clipboard write failed', err);
            notify.error('Copy failed', 'Could not write to clipboard');
        }
    };

    // Trick: we lie to WizardStep about isCompleted so that once at
    // least one employee exists, the primary wizard button flips to
    // "Continue" and the create form stays available below for more
    // adds.
    const pretendCompleted = props.isCompleted || members.length > 0 || createdMembers.length > 0;

    // Build the right pane summary. Every non-admin row gets the
    // copy icon — `canCopyCredentials: true` unconditionally — and
    // the click handler figures out at action time whether to read
    // from in-browser memory or the sidecar's Redis cache. If both
    // are empty (>24h old), the click toasts a "password expired"
    // message instead of silently failing.
    const teamSummaries = useMemo<TeamMemberSummary[]>(
        () =>
            members.map((m) => {
                const seat = agents.find((a) => a.workspaceMemberId === m.id);
                const firstRole = m.roles?.[0] ?? null;
                return {
                    id: m.id,
                    userEmail: m.userEmail,
                    name: m.name,
                    roleLabel: firstRole?.label ?? null,
                    sipExtension: seat?.sipExtension ?? null,
                    isCurrentUser: currentUserEmail !== null && m.userEmail === currentUserEmail,
                    canCopyCredentials: true,
                };
            }),
        [members, agents, currentUserEmail],
    );

    return (
        <WizardStep
            step="team"
            isCompleted={pretendCompleted}
            isLast={props.isLast}
            onPrev={props.onPrev}
            onNext={props.onNext}
            onMarkComplete={handleSave}
            onFinish={props.onFinish}
            saving={saving}
            rightPane={
                <TeamRightPane
                    members={teamSummaries}
                    onEdit={handleEditMember}
                    onCopy={handleCopyCredentials}
                />
            }
        >
            {loading ? (
                <p className="text-sm text-tertiary">Loading team settings…</p>
            ) : (
                <div className="flex flex-col gap-6">
                    <div className="rounded-lg border border-secondary bg-secondary p-4 text-xs text-tertiary">
                        {isEditing ? (
                            <p>
                                Editing an existing employee. You can change their name and role.
                                To change their SIP seat, go to the <b>Telephony</b> step.
                            </p>
                        ) : (
                            <p>
                                Create employees in-place. Each person gets an auto-generated
                                temporary password that you share directly — no email
                                invitations are sent. Click the eye icon to reveal it before
                                you save. After creating CC agents, head to the <b>Telephony</b>{' '}
                                step to assign them SIP seats.
                            </p>
                        )}
                    </div>

                    <EmployeeCreateForm
                        value={values}
                        onChange={setValues}
                        roles={roles}
                        mode={isEditing ? 'edit' : 'create'}
                    />

                    <div className="flex items-center justify-end gap-3">
                        {isEditing && (
                            <Button size="md" color="secondary" isDisabled={saving} onClick={resetForm}>
                                Cancel
                            </Button>
                        )}
                        <button
                            type="button"
                            disabled={saving}
                            onClick={handleSave}
                            className="inline-flex items-center gap-2 rounded-lg bg-brand-solid px-4 py-2 text-sm font-semibold text-primary_on-brand shadow-xs transition hover:bg-brand-solid_hover disabled:opacity-60"
                        >
                            {saving
                                ? isEditing
                                    ? 'Updating…'
                                    : 'Creating…'
                                : isEditing
                                ? 'Update employee'
                                : 'Create employee'}
                        </button>
                    </div>
                </div>
            )}
        </WizardStep>
    );
};

