'use client';

import React, { useState, useCallback, useRef } from 'react';
import {
  Cloud,
  Package,
  Container,
  Download,
  Rocket,
  ArrowLeft,
} from 'lucide-react';
import { cn } from '@/lib/utils';
import type {
  DeployTarget,
  DeployResult,
} from '@mcpengine/ai-pipeline/types';
import {
  DeployStepIndicator,
  type StepState,
} from './DeployStepIndicator';
import { DeployLogViewer, type LogEntry } from './DeployLogViewer';
import { DeploySuccess } from './DeploySuccess';

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

type DeployPhase = 'select' | 'deploying' | 'success' | 'error';

type DeployStep = 'build' | 'test' | 'package' | 'deploy' | 'verify';

interface StepConfig {
  key: DeployStep;
  label: string;
}

const STEPS: StepConfig[] = [
  { key: 'build', label: 'Build' },
  { key: 'test', label: 'Test' },
  { key: 'package', label: 'Package' },
  { key: 'deploy', label: 'Deploy' },
  { key: 'verify', label: 'Verify' },
];

interface TargetOption {
  id: DeployTarget;
  label: string;
  description: string;
  icon: React.ReactNode;
  available: boolean;
  badge?: string;
}

// ---------------------------------------------------------------------------
// Props
// ---------------------------------------------------------------------------

export interface DeployPageProps {
  projectId: string;
  projectName?: string;
  projectSlug?: string;
  className?: string;
}

// ---------------------------------------------------------------------------
// Component
// ---------------------------------------------------------------------------

export function DeployPage({
  projectId,
  projectName = 'MCP Server',
  projectSlug,
  className,
}: DeployPageProps) {
  const [phase, setPhase] = useState<DeployPhase>('select');
  const [selectedTarget, setSelectedTarget] = useState<DeployTarget | null>(null);
  const [stepStates, setStepStates] = useState<Record<DeployStep, StepState>>({
    build: 'waiting',
    test: 'waiting',
    package: 'waiting',
    deploy: 'waiting',
    verify: 'waiting',
  });
  const [logs, setLogs] = useState<LogEntry[]>([]);
  const [result, setResult] = useState<DeployResult | null>(null);
  const [error, setError] = useState<string | null>(null);
  const abortRef = useRef<AbortController | null>(null);

  // ── Target options ─────────────────────────────────────────────────────
  const targets: TargetOption[] = [
    {
      id: 'mcpengine',
      label: 'MCPEngine',
      description: 'Deploy to MCPEngine cloud. Instant, zero-config.',
      icon: <Cloud className="h-6 w-6" />,
      available: true,
      badge: 'Recommended',
    },
    {
      id: 'npm',
      label: 'npm',
      description: 'Publish as an npm package for local installation.',
      icon: <Package className="h-6 w-6" />,
      available: false,
      badge: 'Coming Soon',
    },
    {
      id: 'docker',
      label: 'Docker',
      description: 'Build a Docker image for self-hosted deployment.',
      icon: <Container className="h-6 w-6" />,
      available: false,
      badge: 'Coming Soon',
    },
    {
      id: 'download',
      label: 'Download',
      description: 'Download source code with all config files.',
      icon: <Download className="h-6 w-6" />,
      available: true,
    },
  ];

  // ── Append log ─────────────────────────────────────────────────────────
  const addLog = useCallback(
    (message: string, level: LogEntry['level'] = 'info') => {
      setLogs((prev) => [
        ...prev,
        { timestamp: new Date().toISOString(), message, level },
      ]);
    },
    [],
  );

  // ── Start deploy ───────────────────────────────────────────────────────
  const startDeploy = useCallback(
    async (target: DeployTarget) => {
      setSelectedTarget(target);
      setPhase('deploying');
      setLogs([]);
      setError(null);
      setResult(null);
      setStepStates({
        build: 'active',
        test: 'waiting',
        package: 'waiting',
        deploy: 'waiting',
        verify: 'waiting',
      });

      addLog(`Starting deployment to ${target}…`, 'info');

      const controller = new AbortController();
      abortRef.current = controller;

      try {
        const res = await fetch('/api/deploy', {
          method: 'POST',
          headers: { 'Content-Type': 'application/json' },
          body: JSON.stringify({
            projectId,
            target,
            config: {
              slug: projectSlug ?? projectId.slice(0, 12),
            },
          }),
          signal: controller.signal,
        });

        if (!res.ok) {
          const errData = await res.json().catch(() => ({}));
          throw new Error(errData.error ?? `HTTP ${res.status}`);
        }

        // Read SSE stream
        const reader = res.body?.getReader();
        if (!reader) throw new Error('No response body');

        const decoder = new TextDecoder();
        let buffer = '';

        while (true) {
          const { value, done } = await reader.read();
          if (done) break;

          buffer += decoder.decode(value, { stream: true });
          const lines = buffer.split('\n\n');
          buffer = lines.pop() ?? '';

          for (const line of lines) {
            if (!line.startsWith('data: ')) continue;
            try {
              const event = JSON.parse(line.slice(6));
              handleEvent(event);
            } catch {
              // Skip malformed events
            }
          }
        }
      } catch (err: any) {
        if (err.name === 'AbortError') return;
        const msg = err.message ?? 'Deployment failed';
        addLog(msg, 'error');
        setError(msg);
        setPhase('error');

        // Mark current active step as failed
        setStepStates((prev) => {
          const next = { ...prev };
          for (const step of STEPS) {
            if (next[step.key] === 'active') {
              next[step.key] = 'failed';
            }
          }
          return next;
        });
      }
    },
    [projectId, projectSlug, addLog],
  );

  // ── Handle SSE event ───────────────────────────────────────────────────
  const handleEvent = useCallback(
    (event: any) => {
      const { type, step, message, level, result: eventResult } = event;

      // Add to log
      if (message) {
        addLog(message, level ?? 'info');
      }

      // Update step states
      if (step && type === 'progress') {
        setStepStates((prev) => {
          const next = { ...prev };
          // Complete all steps before current
          const stepIdx = STEPS.findIndex((s) => s.key === step);
          for (let i = 0; i < stepIdx; i++) {
            if (next[STEPS[i].key] !== 'failed') {
              next[STEPS[i].key] = 'complete';
            }
          }
          // Set current step based on level
          if (level === 'success') {
            next[step as DeployStep] = 'complete';
            // Activate next step
            if (stepIdx + 1 < STEPS.length) {
              next[STEPS[stepIdx + 1].key] = 'active';
            }
          } else if (level === 'error') {
            next[step as DeployStep] = 'failed';
          } else {
            next[step as DeployStep] = 'active';
          }
          return next;
        });
      }

      // Deploy complete
      if (type === 'complete' && eventResult) {
        setResult(eventResult);
        setStepStates({
          build: 'complete',
          test: 'complete',
          package: 'complete',
          deploy: 'complete',
          verify: 'complete',
        });
        setTimeout(() => setPhase('success'), 500);
      }

      // Error
      if (type === 'error') {
        setError(message);
        setPhase('error');
      }
    },
    [addLog],
  );

  // ── Reset ──────────────────────────────────────────────────────────────
  const reset = () => {
    abortRef.current?.abort();
    setPhase('select');
    setSelectedTarget(null);
    setLogs([]);
    setError(null);
    setResult(null);
    setStepStates({
      build: 'waiting',
      test: 'waiting',
      package: 'waiting',
      deploy: 'waiting',
      verify: 'waiting',
    });
  };

  // ── Render: Target selection ───────────────────────────────────────────
  if (phase === 'select') {
    return (
      <div className={cn('mx-auto max-w-3xl', className)}>
        <div className="mb-8 text-center">
          <div className="mb-4 inline-flex items-center justify-center rounded-2xl bg-gradient-to-br from-indigo-500/20 to-purple-500/20 p-4">
            <Rocket className="h-8 w-8 text-indigo-400" />
          </div>
          <h1 className="mb-2 text-3xl font-bold text-white">
            Deploy {projectName}
          </h1>
          <p className="text-gray-400">
            Choose a deployment target for your MCP server
          </p>
        </div>

        <div className="grid gap-4 sm:grid-cols-2">
          {targets.map((t) => (
            <button
              key={t.id}
              disabled={!t.available}
              onClick={() => t.available && startDeploy(t.id)}
              className={cn(
                'group relative flex flex-col items-start gap-3 rounded-2xl border p-6 text-left transition-all duration-200',
                t.available
                  ? 'border-gray-700 bg-gray-800/50 hover:border-indigo-500/50 hover:bg-gray-800 hover:shadow-lg hover:shadow-indigo-500/10 cursor-pointer'
                  : 'border-gray-800 bg-gray-900/50 opacity-60 cursor-not-allowed',
              )}
            >
              {/* Badge */}
              {t.badge && (
                <span
                  className={cn(
                    'absolute right-4 top-4 rounded-full px-2.5 py-0.5 text-[10px] font-semibold uppercase tracking-wider',
                    t.badge === 'Recommended'
                      ? 'bg-indigo-500/20 text-indigo-400'
                      : 'bg-gray-700 text-gray-400',
                  )}
                >
                  {t.badge}
                </span>
              )}

              {/* Icon */}
              <div
                className={cn(
                  'flex h-12 w-12 items-center justify-center rounded-xl transition-colors',
                  t.available
                    ? 'bg-indigo-500/10 text-indigo-400 group-hover:bg-indigo-500/20'
                    : 'bg-gray-800 text-gray-500',
                )}
              >
                {t.icon}
              </div>

              {/* Label & description */}
              <div>
                <h3 className="text-lg font-semibold text-white">
                  {t.label}
                </h3>
                <p className="mt-1 text-sm text-gray-400">{t.description}</p>
              </div>
            </button>
          ))}
        </div>
      </div>
    );
  }

  // ── Render: Deploying / Error ──────────────────────────────────────────
  if (phase === 'deploying' || phase === 'error') {
    return (
      <div className={cn('mx-auto max-w-3xl', className)}>
        {/* Back button */}
        <button
          onClick={reset}
          className="mb-6 flex items-center gap-2 text-sm text-gray-400 transition-colors hover:text-white"
        >
          <ArrowLeft className="h-4 w-4" />
          Back to targets
        </button>

        {/* Header */}
        <div className="mb-8 text-center">
          <h1 className="mb-2 text-2xl font-bold text-white">
            Deploying to{' '}
            <span className="bg-gradient-to-r from-indigo-400 to-purple-400 bg-clip-text text-transparent">
              {selectedTarget}
            </span>
          </h1>
          <p className="text-gray-400">{projectName}</p>
        </div>

        {/* Step indicator */}
        <div className="mb-8 flex items-start justify-center">
          {STEPS.map((step, i) => (
            <DeployStepIndicator
              key={step.key}
              label={step.label}
              state={stepStates[step.key]}
              index={i}
              isLast={i === STEPS.length - 1}
            />
          ))}
        </div>

        {/* Error banner */}
        {phase === 'error' && error && (
          <div className="mb-6 rounded-xl border border-red-500/30 bg-red-500/10 px-4 py-3 text-sm text-red-300">
            <strong>Error:</strong> {error}
          </div>
        )}

        {/* Log viewer */}
        <DeployLogViewer logs={logs} maxHeight="360px" />

        {/* Retry on error */}
        {phase === 'error' && selectedTarget && (
          <div className="mt-6 flex justify-center gap-3">
            <button
              onClick={reset}
              className="rounded-xl border border-gray-700 bg-gray-800 px-5 py-2.5 text-sm font-medium text-gray-300 hover:bg-gray-700"
            >
              Back
            </button>
            <button
              onClick={() => startDeploy(selectedTarget)}
              className="rounded-xl bg-gradient-to-r from-indigo-600 to-purple-600 px-5 py-2.5 text-sm font-medium text-white shadow-lg shadow-indigo-500/25 hover:shadow-indigo-500/40"
            >
              Retry Deploy
            </button>
          </div>
        )}
      </div>
    );
  }

  // ── Render: Success ────────────────────────────────────────────────────
  if (phase === 'success' && result) {
    return (
      <div className={cn('mx-auto max-w-3xl', className)}>
        <DeploySuccess
          result={result}
          serverName={projectName}
          onDashboard={() => {
            window.location.href = `/projects/${projectId}`;
          }}
          onViewServer={() => {
            if (result.url) window.open(result.url, '_blank');
          }}
          onDeployAnother={reset}
        />
      </div>
    );
  }

  return null;
}
