'use client';

import { useMemo, useState } from 'react';
import { useRouter } from 'next/navigation';
import { Icons } from '@/components/icons';
import { Alert, AlertDescription, AlertTitle } from '@/components/ui/alert';
import { Badge } from '@/components/ui/badge';
import { Button } from '@/components/ui/button';
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '@/components/ui/card';
import { Input } from '@/components/ui/input';
import type { CsvPreviewResult, ImportReport } from '@/features/setup/api/types';

interface BootstrapSetupProps {
  tokenRequired: boolean;
  requiredFiles: string[];
  optionalFiles: string[];
}

interface ApiErrorPayload {
  message?: string;
  details?: {
    missingFiles?: string[];
  };
}

function isApiErrorPayload(value: unknown): value is ApiErrorPayload {
  return Boolean(value && typeof value === 'object');
}

function getFileMap(files: File[]) {
  return new Map(files.map((file) => [file.name.toLowerCase(), file]));
}

function getErrorMessage(error: unknown) {
  if (error instanceof Error) return error.message;
  return 'Request failed.';
}

async function readJsonResponse<T>(response: Response): Promise<T> {
  const payload = (await response.json().catch(() => ({}))) as unknown;

  if (!response.ok) {
    const message = isApiErrorPayload(payload) && payload.message ? payload.message : 'Request failed.';
    throw new Error(message);
  }

  return payload as T;
}

function appendFiles(formData: FormData, files: File[]) {
  files.forEach((file) => {
    formData.append('files', file, file.name);
  });
}

function StatusBadge({ status }: { status: 'PASS' | 'WARNING' | 'FAIL' }) {
  const variant = status === 'FAIL' ? 'destructive' : status === 'WARNING' ? 'secondary' : 'default';
  return <Badge variant={variant}>{status}</Badge>;
}

export function BootstrapSetup({ tokenRequired, requiredFiles, optionalFiles }: BootstrapSetupProps) {
  const router = useRouter();
  const [files, setFiles] = useState<File[]>([]);
  const [bootstrapToken, setBootstrapToken] = useState('');
  const [preview, setPreview] = useState<CsvPreviewResult | null>(null);
  const [commitReport, setCommitReport] = useState<ImportReport | null>(null);
  const [isPreviewing, setIsPreviewing] = useState(false);
  const [isCommitting, setIsCommitting] = useState(false);
  const [isCompleting, setIsCompleting] = useState(false);
  const [error, setError] = useState<string | null>(null);

  const fileMap = useMemo(() => getFileMap(files), [files]);
  const missingRequiredFiles = requiredFiles.filter((fileName) => !fileMap.has(fileName.toLowerCase()));
  const selectedOptionalCount = optionalFiles.filter((fileName) => fileMap.has(fileName.toLowerCase())).length;
  const canPreview = missingRequiredFiles.length === 0 && files.length > 0 && (!tokenRequired || bootstrapToken.length > 0);
  const canCommit = Boolean(preview?.previewHash) && preview?.summary.error === 0 && canPreview;
  const canComplete = Boolean(commitReport && commitReport.status !== 'FAIL');

  function handleFiles(fileList: FileList | null) {
    setFiles(Array.from(fileList ?? []));
    setPreview(null);
    setCommitReport(null);
    setError(null);
  }

  async function runPreview() {
    setIsPreviewing(true);
    setError(null);

    try {
      const formData = new FormData();
      formData.set('bootstrapToken', bootstrapToken);
      appendFiles(formData, files);

      const response = await fetch('/api/setup/bootstrap/preview', {
        method: 'POST',
        body: formData
      });
      const result = await readJsonResponse<CsvPreviewResult>(response);
      setPreview(result);
    } catch (requestError) {
      setError(getErrorMessage(requestError));
    } finally {
      setIsPreviewing(false);
    }
  }

  async function runCommit() {
    if (!preview?.previewHash) return;

    setIsCommitting(true);
    setError(null);

    try {
      const formData = new FormData();
      formData.set('bootstrapToken', bootstrapToken);
      formData.set('previewHash', preview.previewHash);
      appendFiles(formData, files);

      const response = await fetch('/api/setup/bootstrap/commit', {
        method: 'POST',
        body: formData
      });
      const result = await readJsonResponse<ImportReport>(response);
      setCommitReport(result);
    } catch (requestError) {
      setError(getErrorMessage(requestError));
    } finally {
      setIsCommitting(false);
    }
  }

  async function completeSetup() {
    setIsCompleting(true);
    setError(null);

    try {
      const response = await fetch('/api/setup/bootstrap/complete', {
        method: 'POST',
        headers: { 'content-type': 'application/json' },
        body: JSON.stringify({ bootstrapToken })
      });
      await readJsonResponse(response);
      router.replace('/auth/sign-in');
    } catch (requestError) {
      setError(getErrorMessage(requestError));
    } finally {
      setIsCompleting(false);
    }
  }

  return (
    <main className='min-h-screen bg-background px-4 py-8 md:px-8'>
      <div className='mx-auto flex w-full max-w-6xl flex-col gap-6'>
        <div className='space-y-2'>
          <Badge variant='secondary'>First-run bootstrap</Badge>
          <h1 className='text-3xl font-semibold tracking-normal'>ALLA OS Setup</h1>
          <p className='max-w-3xl text-sm text-muted-foreground'>
            Upload the official setup CSV files, validate them, commit the initial organization data,
            then sign in with the administrator account from users.csv.
          </p>
        </div>

        <Alert>
          <Icons.lock className='h-4 w-4' />
          <AlertTitle>Public only before initialization</AlertTitle>
          <AlertDescription>
            This bootstrap page is available only until setup is completed. After completion, setup
            maintenance moves to the authenticated dashboard administration page.
          </AlertDescription>
        </Alert>

        {error ? (
          <Alert variant='destructive'>
            <Icons.alertCircle className='h-4 w-4' />
            <AlertTitle>Setup request failed</AlertTitle>
            <AlertDescription>{error}</AlertDescription>
          </Alert>
        ) : null}

        <div className='grid gap-6 lg:grid-cols-[1fr_360px]'>
          <section className='space-y-6'>
            <Card>
              <CardHeader>
                <CardTitle>CSV Upload</CardTitle>
                <CardDescription>Required foundation files must be selected before preview.</CardDescription>
              </CardHeader>
              <CardContent className='space-y-4'>
                {tokenRequired ? (
                  <Input
                    type='password'
                    value={bootstrapToken}
                    onChange={(event) => setBootstrapToken(event.target.value)}
                    placeholder='Bootstrap setup token'
                    aria-label='Bootstrap setup token'
                  />
                ) : null}

                <Input type='file' multiple accept='.csv,text/csv' onChange={(event) => handleFiles(event.target.files)} />

                <div className='grid gap-2 sm:grid-cols-2'>
                  {files.map((file) => (
                    <div key={`${file.name}-${file.size}-${file.lastModified}`} className='rounded-md border p-3 text-sm'>
                      <div className='font-medium'>{file.name}</div>
                      <div className='text-muted-foreground'>{file.size} bytes</div>
                    </div>
                  ))}
                </div>

                {missingRequiredFiles.length > 0 ? (
                  <Alert>
                    <Icons.info className='h-4 w-4' />
                    <AlertTitle>Required files missing</AlertTitle>
                    <AlertDescription>{missingRequiredFiles.join(', ')}</AlertDescription>
                  </Alert>
                ) : null}

                <div className='flex flex-wrap gap-2'>
                  <Button type='button' onClick={runPreview} disabled={!canPreview || isPreviewing}>
                    {isPreviewing ? (
                      <Icons.spinner className='mr-2 h-4 w-4 animate-spin' />
                    ) : (
                      <Icons.upload className='mr-2 h-4 w-4' />
                    )}
                    Preview CSV
                  </Button>
                  <Button type='button' variant='outline' onClick={runCommit} disabled={!canCommit || isCommitting}>
                    {isCommitting ? (
                      <Icons.spinner className='mr-2 h-4 w-4 animate-spin' />
                    ) : (
                      <Icons.check className='mr-2 h-4 w-4' />
                    )}
                    Setup System
                  </Button>
                </div>
              </CardContent>
            </Card>

            <Card>
              <CardHeader>
                <CardTitle>Preview Result</CardTitle>
                <CardDescription>Commit is enabled only when preview has no blocking errors.</CardDescription>
              </CardHeader>
              <CardContent className='space-y-4'>
                {preview ? (
                  <>
                    <div className='flex flex-wrap items-center justify-between gap-3'>
                      <div className='min-w-0'>
                        <div className='font-medium'>Preview hash</div>
                        <div className='break-all text-sm text-muted-foreground'>{preview.previewHash}</div>
                      </div>
                      <StatusBadge status={preview.summary.error > 0 ? 'FAIL' : preview.summary.warning > 0 ? 'WARNING' : 'PASS'} />
                    </div>
                    <div className='grid gap-2 sm:grid-cols-5'>
                      <Metric label='Files' value={preview.summary.files} />
                      <Metric label='Rows' value={preview.summary.rows} />
                      <Metric label='Create' value={preview.summary.create} />
                      <Metric label='Warning' value={preview.summary.warning} />
                      <Metric label='Error' value={preview.summary.error} />
                    </div>
                  </>
                ) : (
                  <EmptyPanel message='Preview has not run yet.' />
                )}
              </CardContent>
            </Card>

            <Card>
              <CardHeader>
                <CardTitle>Completion</CardTitle>
                <CardDescription>Finish setup after data commit succeeds.</CardDescription>
              </CardHeader>
              <CardContent className='space-y-4'>
                {commitReport ? (
                  <div className='grid gap-2 sm:grid-cols-5'>
                    <Metric label='Imported' value={commitReport.summary.imported} />
                    <Metric label='Updated' value={commitReport.summary.updated} />
                    <Metric label='Skipped' value={commitReport.summary.skipped} />
                    <Metric label='Warnings' value={commitReport.summary.warnings} />
                    <Metric label='Errors' value={commitReport.summary.errors} />
                  </div>
                ) : (
                  <EmptyPanel message='Commit has not run yet.' />
                )}

                <Button type='button' onClick={completeSetup} disabled={!canComplete || isCompleting}>
                  {isCompleting ? (
                    <Icons.spinner className='mr-2 h-4 w-4 animate-spin' />
                  ) : (
                    <Icons.arrowRight className='mr-2 h-4 w-4' />
                  )}
                  Complete and go to login
                </Button>
              </CardContent>
            </Card>
          </section>

          <aside className='space-y-6'>
            <Card>
              <CardHeader>
                <CardTitle>Required Template Checklist</CardTitle>
                <CardDescription>Foundation, document sequence, and approval setup.</CardDescription>
              </CardHeader>
              <CardContent className='space-y-2'>
                {requiredFiles.map((fileName) => (
                  <TemplateChecklistItem key={fileName} fileName={fileName} selected={fileMap.has(fileName.toLowerCase())} />
                ))}
              </CardContent>
            </Card>

            <Card>
              <CardHeader>
                <CardTitle>Business CSV</CardTitle>
                <CardDescription>Optional files selected: {selectedOptionalCount}</CardDescription>
              </CardHeader>
              <CardContent className='space-y-2'>
                {optionalFiles.map((fileName) => (
                  <TemplateChecklistItem key={fileName} fileName={fileName} selected={fileMap.has(fileName.toLowerCase())} />
                ))}
              </CardContent>
            </Card>
          </aside>
        </div>
      </div>
    </main>
  );
}

function TemplateChecklistItem({ fileName, selected }: { fileName: string; selected: boolean }) {
  return (
    <div className='flex items-center justify-between gap-3 rounded-md border px-3 py-2 text-sm'>
      <span className='min-w-0 truncate'>{fileName}</span>
      <Badge variant={selected ? 'default' : 'secondary'}>{selected ? 'Selected' : 'Missing'}</Badge>
    </div>
  );
}

function Metric({ label, value }: { label: string; value: number | string }) {
  return (
    <div className='rounded-md border p-3'>
      <div className='text-xs font-medium uppercase text-muted-foreground'>{label}</div>
      <div className='text-lg font-semibold'>{value}</div>
    </div>
  );
}

function EmptyPanel({ message }: { message: string }) {
  return <div className='rounded-md border border-dashed p-6 text-center text-sm text-muted-foreground'>{message}</div>;
}
