'use client';

import React, { useState } from 'react';

// ---------------------------------------------------------------------------
// Types
// ---------------------------------------------------------------------------

type Sdk = 'nodejs' | 'python' | 'go' | 'java';

interface WizardState {
  step: 1 | 2 | 3 | 4;
  agentName: string;
  agentId: string | null;
  clientId: string | null;
  clientSecret: string | null;
  selectedSdk: Sdk;
  loading: boolean;
  error: string | null;
}

interface AgentCreateResponse {
  agentId: string;
}

interface CredentialsResponse {
  clientId: string;
  clientSecret: string;
}

// ---------------------------------------------------------------------------
// SDK code snippets
// ---------------------------------------------------------------------------

function buildSnippet(
  sdk: Sdk,
  apiUrl: string,
  clientId: string,
  clientSecret: string
): string {
  switch (sdk) {
    case 'nodejs':
      return `import { AgentIdPClient } from '@sentryagent/idp-sdk';

const client = new AgentIdPClient({
  apiUrl: '${apiUrl}',
  clientId: '${clientId}',
  clientSecret: '${clientSecret}',
});

const { accessToken } = await client.tokens.issue();
console.log('Access token:', accessToken);`;

    case 'python':
      return `from sentryagent_idp import AgentIdPClient

client = AgentIdPClient(
    api_url="${apiUrl}",
    client_id="${clientId}",
    client_secret="${clientSecret}",
)

token_response = client.tokens.issue()
print("Access token:", token_response.access_token)`;

    case 'go':
      return `import idp "github.com/sentryagent/idp-sdk-go"

client := idp.NewClient(idp.Config{
    APIURL:       "${apiUrl}",
    ClientID:     "${clientId}",
    ClientSecret: "${clientSecret}",
})

token, err := client.Tokens.Issue(ctx)
if err != nil {
    panic(err)
}
fmt.Println("Access token:", token.AccessToken)`;

    case 'java':
      return `AgentIdPClient client = AgentIdPClient.builder()
    .apiUrl("${apiUrl}")
    .clientId("${clientId}")
    .clientSecret("${clientSecret}")
    .build();

TokenResponse token = client.tokens().issue();
System.out.println("Access token: " + token.getAccessToken());`;

    default:
      return '';
  }
}

// ---------------------------------------------------------------------------
// Shared UI helpers
// ---------------------------------------------------------------------------

function StepIndicator({
  current,
  total,
}: {
  current: number;
  total: number;
}): React.ReactElement {
  return (
    <div className="mb-8 flex items-center gap-2">
      {Array.from({ length: total }, (_, i) => i + 1).map((n) => (
        <React.Fragment key={n}>
          <div
            className={[
              'flex h-8 w-8 items-center justify-center rounded-full text-sm font-bold',
              n < current
                ? 'bg-brand-600 text-white'
                : n === current
                  ? 'border-2 border-brand-600 bg-brand-50 text-brand-700'
                  : 'bg-slate-200 text-slate-500',
            ].join(' ')}
          >
            {n < current ? '✓' : n}
          </div>
          {n < total && (
            <div
              className={[
                'h-0.5 flex-1',
                n < current ? 'bg-brand-600' : 'bg-slate-200',
              ].join(' ')}
            />
          )}
        </React.Fragment>
      ))}
    </div>
  );
}

function CopyButton({ text }: { text: string }): React.ReactElement {
  const [copied, setCopied] = useState(false);

  const handleCopy = async (): Promise<void> => {
    await navigator.clipboard.writeText(text);
    setCopied(true);
    setTimeout(() => setCopied(false), 2000);
  };

  return (
    <button
      onClick={() => void handleCopy()}
      className="ml-2 rounded bg-slate-100 px-2 py-1 text-xs font-medium text-slate-600 transition-colors hover:bg-slate-200"
    >
      {copied ? 'Copied!' : 'Copy'}
    </button>
  );
}

function ErrorAlert({ message }: { message: string }): React.ReactElement {
  return (
    <div className="mb-4 rounded-lg border border-red-200 bg-red-50 px-4 py-3 text-sm text-red-700">
      {message}
    </div>
  );
}

// ---------------------------------------------------------------------------
// Step components
// ---------------------------------------------------------------------------

function Step1AccountSetup({
  onNext,
}: {
  onNext: () => void;
}): React.ReactElement {
  return (
    <div>
      <h2 className="mb-2 text-2xl font-bold text-slate-900">
        Step 1: Account Setup
      </h2>
      <p className="mb-6 text-slate-600">
        Before registering your first agent, make sure you have the AgentIdP
        server running.
      </p>

      <ol className="mb-8 space-y-4">
        {[
          {
            n: 1,
            title: 'Clone the repository',
            code: 'git clone https://github.com/sentryagent/sentryagent-idp.git',
          },
          {
            n: 2,
            title: 'Copy environment variables',
            code: 'cp .env.example .env',
          },
          {
            n: 3,
            title: 'Start the server',
            code: 'docker compose up -d && npm run db:migrate',
          },
          {
            n: 4,
            title: 'Verify the server is healthy',
            code: 'curl http://localhost:3000/health',
          },
        ].map(({ n, title, code }) => (
          <li key={n} className="flex gap-4">
            <span className="mt-0.5 flex h-6 w-6 flex-shrink-0 items-center justify-center rounded-full bg-brand-600 text-xs font-bold text-white">
              {n}
            </span>
            <div className="flex-1">
              <p className="mb-1 font-medium text-slate-800">{title}</p>
              <div className="flex items-center rounded-lg bg-slate-900 px-3 py-2">
                <code className="flex-1 text-sm text-slate-100">{code}</code>
                <CopyButton text={code} />
              </div>
            </div>
          </li>
        ))}
      </ol>

      <button
        onClick={onNext}
        className="rounded-lg bg-brand-600 px-6 py-2.5 font-semibold text-white transition-colors hover:bg-brand-700"
      >
        My server is running &rarr;
      </button>
    </div>
  );
}

function Step2RegisterAgent({
  agentName,
  onAgentNameChange,
  agentId,
  loading,
  error,
  onRegister,
  onNext,
}: {
  agentName: string;
  onAgentNameChange: (v: string) => void;
  agentId: string | null;
  loading: boolean;
  error: string | null;
  onRegister: () => void;
  onNext: () => void;
}): React.ReactElement {
  return (
    <div>
      <h2 className="mb-2 text-2xl font-bold text-slate-900">
        Step 2: Register Your Agent
      </h2>
      <p className="mb-6 text-slate-600">
        Give your agent a name and register it with AgentIdP. You will receive a
        unique Agent ID.
      </p>

      {error && <ErrorAlert message={error} />}

      {agentId ? (
        <div className="mb-6 rounded-xl border border-green-200 bg-green-50 p-6">
          <p className="mb-1 text-sm font-semibold text-green-700">
            Agent registered successfully!
          </p>
          <div className="flex items-center gap-2">
            <p className="text-sm text-slate-700">
              Agent ID:{' '}
              <code className="rounded bg-slate-100 px-1.5 py-0.5 font-mono text-sm">
                {agentId}
              </code>
            </p>
            <CopyButton text={agentId} />
          </div>
        </div>
      ) : (
        <div className="mb-6">
          <label
            htmlFor="agent-name"
            className="mb-1.5 block text-sm font-medium text-slate-700"
          >
            Agent Name
          </label>
          <div className="flex gap-3">
            <input
              id="agent-name"
              type="text"
              value={agentName}
              onChange={(e) => onAgentNameChange(e.target.value)}
              placeholder="e.g. my-summarisation-agent"
              className="flex-1 rounded-lg border border-slate-300 px-4 py-2.5 text-sm focus:border-brand-500 focus:outline-none focus:ring-2 focus:ring-brand-200"
            />
            <button
              onClick={onRegister}
              disabled={loading || agentName.trim() === ''}
              className="rounded-lg bg-brand-600 px-5 py-2.5 text-sm font-semibold text-white transition-colors hover:bg-brand-700 disabled:cursor-not-allowed disabled:opacity-50"
            >
              {loading ? 'Registering…' : 'Register Agent'}
            </button>
          </div>
        </div>
      )}

      {agentId && (
        <button
          onClick={onNext}
          className="rounded-lg bg-brand-600 px-6 py-2.5 font-semibold text-white transition-colors hover:bg-brand-700"
        >
          Generate Credentials &rarr;
        </button>
      )}
    </div>
  );
}

function Step3GenerateCredentials({
  agentId,
  clientId,
  clientSecret,
  loading,
  error,
  onGenerate,
  onNext,
}: {
  agentId: string;
  clientId: string | null;
  clientSecret: string | null;
  loading: boolean;
  error: string | null;
  onGenerate: () => void;
  onNext: () => void;
}): React.ReactElement {
  return (
    <div>
      <h2 className="mb-2 text-2xl font-bold text-slate-900">
        Step 3: Generate Credentials
      </h2>
      <p className="mb-6 text-slate-600">
        Generate OAuth 2.0 client credentials for agent{' '}
        <code className="rounded bg-slate-100 px-1.5 py-0.5 text-sm">
          {agentId}
        </code>
        . Store your client secret securely — it will not be shown again.
      </p>

      {error && <ErrorAlert message={error} />}

      {clientId && clientSecret ? (
        <div className="mb-6 space-y-4">
          <div className="rounded-xl border border-brand-200 bg-brand-50 p-5">
            <p className="mb-3 text-sm font-semibold text-brand-700">
              Credentials generated. Store these securely!
            </p>

            <div className="space-y-3">
              <div>
                <p className="mb-1 text-xs font-semibold uppercase tracking-wider text-slate-500">
                  Client ID
                </p>
                <div className="flex items-center gap-2 rounded-lg bg-white px-3 py-2 shadow-sm">
                  <code className="flex-1 break-all font-mono text-sm text-slate-800">
                    {clientId}
                  </code>
                  <CopyButton text={clientId} />
                </div>
              </div>

              <div>
                <p className="mb-1 text-xs font-semibold uppercase tracking-wider text-slate-500">
                  Client Secret
                </p>
                <div className="flex items-center gap-2 rounded-lg bg-white px-3 py-2 shadow-sm">
                  <code className="flex-1 break-all font-mono text-sm text-slate-800">
                    {clientSecret}
                  </code>
                  <CopyButton text={clientSecret} />
                </div>
              </div>
            </div>
          </div>
        </div>
      ) : (
        <button
          onClick={onGenerate}
          disabled={loading}
          className="mb-6 rounded-lg bg-brand-600 px-6 py-2.5 font-semibold text-white transition-colors hover:bg-brand-700 disabled:cursor-not-allowed disabled:opacity-50"
        >
          {loading ? 'Generating…' : 'Generate Credentials'}
        </button>
      )}

      {clientId && clientSecret && (
        <button
          onClick={onNext}
          className="rounded-lg bg-brand-600 px-6 py-2.5 font-semibold text-white transition-colors hover:bg-brand-700"
        >
          Choose Your SDK &rarr;
        </button>
      )}
    </div>
  );
}

const SDK_OPTIONS: { id: Sdk; label: string; description: string }[] = [
  {
    id: 'nodejs',
    label: 'Node.js / TypeScript',
    description: 'npm install @sentryagent/idp-sdk',
  },
  {
    id: 'python',
    label: 'Python',
    description: 'pip install sentryagent-idp',
  },
  {
    id: 'go',
    label: 'Go',
    description: 'go get github.com/sentryagent/idp-sdk-go',
  },
  {
    id: 'java',
    label: 'Java',
    description: 'Maven / Gradle — ai.sentryagent:idp-sdk:1.0.0',
  },
];

function Step4SdkSelection({
  selectedSdk,
  onSdkChange,
  clientId,
  clientSecret,
  apiUrl,
}: {
  selectedSdk: Sdk;
  onSdkChange: (sdk: Sdk) => void;
  clientId: string;
  clientSecret: string;
  apiUrl: string;
}): React.ReactElement {
  const snippet = buildSnippet(selectedSdk, apiUrl, clientId, clientSecret);

  return (
    <div>
      <h2 className="mb-2 text-2xl font-bold text-slate-900">
        Step 4: Choose Your SDK
      </h2>
      <p className="mb-6 text-slate-600">
        Select your language and copy the ready-to-run code snippet below. Your
        credentials are pre-filled.
      </p>

      <div className="mb-6 grid grid-cols-2 gap-3 sm:grid-cols-4">
        {SDK_OPTIONS.map(({ id, label, description }) => (
          <button
            key={id}
            onClick={() => onSdkChange(id)}
            className={[
              'rounded-xl border p-4 text-left transition-all',
              selectedSdk === id
                ? 'border-brand-500 bg-brand-50 shadow-md'
                : 'border-slate-200 bg-white hover:border-brand-300 hover:bg-brand-50',
            ].join(' ')}
          >
            <p
              className={[
                'mb-1 text-sm font-semibold',
                selectedSdk === id ? 'text-brand-700' : 'text-slate-800',
              ].join(' ')}
            >
              {label}
            </p>
            <p className="text-xs text-slate-500">{description}</p>
          </button>
        ))}
      </div>

      <div>
        <div className="mb-2 flex items-center justify-between">
          <p className="text-sm font-semibold uppercase tracking-wider text-slate-500">
            Ready-to-run code
          </p>
          <CopyButton text={snippet} />
        </div>
        <pre className="overflow-x-auto rounded-xl bg-slate-900 px-5 py-5 text-sm leading-relaxed text-slate-100">
          <code>{snippet}</code>
        </pre>
      </div>

      <div className="mt-8 rounded-xl border border-green-200 bg-green-50 p-5 text-center">
        <p className="text-lg font-bold text-green-800">
          You are all set!
        </p>
        <p className="mt-1 text-sm text-green-700">
          Your agent is registered and you have credentials. Start making
          authenticated API calls using the snippet above.
        </p>
      </div>
    </div>
  );
}

// ---------------------------------------------------------------------------
// Main wizard component
// ---------------------------------------------------------------------------

interface GetStartedWizardProps {
  apiUrl: string;
}

export function GetStartedWizard({
  apiUrl,
}: GetStartedWizardProps): React.ReactElement {
  const [state, setState] = useState<WizardState>({
    step: 1,
    agentName: '',
    agentId: null,
    clientId: null,
    clientSecret: null,
    selectedSdk: 'nodejs',
    loading: false,
    error: null,
  });

  const goToStep = (step: WizardState['step']): void => {
    setState((prev) => ({ ...prev, step, error: null }));
  };

  const handleAgentNameChange = (value: string): void => {
    setState((prev) => ({ ...prev, agentName: value }));
  };

  const handleSdkChange = (sdk: Sdk): void => {
    setState((prev) => ({ ...prev, selectedSdk: sdk }));
  };

  const handleRegisterAgent = async (): Promise<void> => {
    setState((prev) => ({ ...prev, loading: true, error: null }));

    try {
      const response = await fetch(`${apiUrl}/agents`, {
        method: 'POST',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify({ name: state.agentName.trim() }),
      });

      if (!response.ok) {
        const body = (await response.json()) as { message?: string };
        throw new Error(body.message ?? `HTTP ${response.status}`);
      }

      const data = (await response.json()) as AgentCreateResponse;
      setState((prev) => ({
        ...prev,
        agentId: data.agentId,
        loading: false,
        error: null,
      }));
    } catch (err) {
      setState((prev) => ({
        ...prev,
        loading: false,
        error: err instanceof Error ? err.message : 'Failed to register agent',
      }));
    }
  };

  const handleGenerateCredentials = async (): Promise<void> => {
    if (!state.agentId) return;

    setState((prev) => ({ ...prev, loading: true, error: null }));

    try {
      const response = await fetch(
        `${apiUrl}/agents/${state.agentId}/credentials`,
        {
          method: 'POST',
          headers: { 'Content-Type': 'application/json' },
        }
      );

      if (!response.ok) {
        const body = (await response.json()) as { message?: string };
        throw new Error(body.message ?? `HTTP ${response.status}`);
      }

      const data = (await response.json()) as CredentialsResponse;
      setState((prev) => ({
        ...prev,
        clientId: data.clientId,
        clientSecret: data.clientSecret,
        loading: false,
        error: null,
      }));
    } catch (err) {
      setState((prev) => ({
        ...prev,
        loading: false,
        error:
          err instanceof Error
            ? err.message
            : 'Failed to generate credentials',
      }));
    }
  };

  const stepLabels = [
    'Account Setup',
    'Register Agent',
    'Generate Credentials',
    'Choose SDK',
  ];

  return (
    <div className="mx-auto max-w-3xl">
      {/* Step label row */}
      <div className="mb-2 flex gap-2 text-xs font-medium text-slate-500">
        {stepLabels.map((label, i) => (
          <span
            key={label}
            className={[
              'flex-1 text-center',
              i + 1 === state.step ? 'font-bold text-brand-700' : '',
            ].join(' ')}
          >
            {label}
          </span>
        ))}
      </div>

      <StepIndicator current={state.step} total={4} />

      <div className="rounded-2xl border border-slate-200 bg-white p-8 shadow-sm">
        {state.step === 1 && (
          <Step1AccountSetup onNext={() => goToStep(2)} />
        )}

        {state.step === 2 && (
          <Step2RegisterAgent
            agentName={state.agentName}
            onAgentNameChange={handleAgentNameChange}
            agentId={state.agentId}
            loading={state.loading}
            error={state.error}
            onRegister={() => void handleRegisterAgent()}
            onNext={() => goToStep(3)}
          />
        )}

        {state.step === 3 && state.agentId && (
          <Step3GenerateCredentials
            agentId={state.agentId}
            clientId={state.clientId}
            clientSecret={state.clientSecret}
            loading={state.loading}
            error={state.error}
            onGenerate={() => void handleGenerateCredentials()}
            onNext={() => goToStep(4)}
          />
        )}

        {state.step === 4 &&
          state.clientId &&
          state.clientSecret && (
            <Step4SdkSelection
              selectedSdk={state.selectedSdk}
              onSdkChange={handleSdkChange}
              clientId={state.clientId}
              clientSecret={state.clientSecret}
              apiUrl={apiUrl}
            />
          )}
      </div>
    </div>
  );
}
