'use client';

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

const defaultApiBase =
  process.env.NODE_ENV === 'production'
    ? 'https://backend.basetracker.lona-development.org'
    : 'http://localhost:4100';

const API_BASE = process.env.NEXT_PUBLIC_BACKEND_URL ?? defaultApiBase;

const API = {
  signup: `${API_BASE}/auth/signup`,
  login: `${API_BASE}/auth/login`,
  logout: `${API_BASE}/auth/logout`,
  me: `${API_BASE}/auth/me`,
  categories: `${API_BASE}/army-categories`,
  bases: `${API_BASE}/bases`,
  addDefense: (baseId: string) => `${API_BASE}/bases/${baseId}/defenses`,
  defenses: `${API_BASE}/defenses`,
};

type User = {
  id: string;
  username: string;
  createdAt: string;
};

type ArmyCategory = {
  id: string;
  name: string;
  createdAt: string;
};

type BaseItem = {
  id: string;
  title: string;
  description: string;
  url: string;
  imageUrl: string;
  createdAt: string;
};

type DefenseItem = {
  id: string;
  stars: number;
  percent: number;
  trophies: number;
  armyCategoryId: string;
  createdAt: string;
  baseId: string;
  baseTitle: string;
  categoryName?: string;
};

type Summary = {
  count: number;
  averageStars: number;
  averagePercent: number;
  averageTrophies: number;
};

type BaseSummary = Summary & {
  baseId: string;
  title: string;
  categories: Array<Summary & { categoryId: string; name: string }>;
};

type CategorySummary = Summary & {
  categoryId: string;
  name: string;
  bases: Array<Summary & { baseId: string; title: string }>;
};

type Summaries = {
  overall: Summary;
  categories: CategorySummary[];
  bases: BaseSummary[];
};

type ErrorState = {
  login: string;
  signup: string;
  category: string;
  base: string;
  defense: string;
};

async function request(method: string, url: string, body?: any, options?: { isForm?: boolean }) {
  const isForm = options?.isForm ?? false;
  const fetchOptions: RequestInit = {
    method,
    credentials: 'include',
  };

  if (isForm && body instanceof FormData) {
    fetchOptions.body = body;
  } else if (body !== undefined) {
    fetchOptions.headers = { 'Content-Type': 'application/json' };
    fetchOptions.body = JSON.stringify(body);
  }

  const response = await fetch(url, fetchOptions);
  const contentType = response.headers.get('content-type') ?? '';
  const data = contentType.includes('application/json') ? await response.json() : {};
  if (!response.ok) {
    const message = (data && data.error) || 'Something went wrong';
    throw new Error(message);
  }
  return data;
}

const initialErrors: ErrorState = {
  login: '',
  signup: '',
  category: '',
  base: '',
  defense: '',
};

export default function Page() {
  const [authTab, setAuthTab] = useState<'login' | 'signup'>('login');
  const [view, setView] = useState<'dashboard' | 'forms' | 'baseDetail' | 'categoryDetail'>('dashboard');
  const [user, setUser] = useState<User | null>(null);
  const [categories, setCategories] = useState<ArmyCategory[]>([]);
  const [bases, setBases] = useState<BaseItem[]>([]);
  const [defenses, setDefenses] = useState<DefenseItem[]>([]);
  const [summaries, setSummaries] = useState<Summaries | null>(null);
  const [selectedBaseId, setSelectedBaseId] = useState<string | null>(null);
  const [selectedCategoryId, setSelectedCategoryId] = useState<string | null>(null);
  const [errors, setErrors] = useState<ErrorState>(initialErrors);
  const [imageMode, setImageMode] = useState<'upload' | 'url'>('upload');
  const [loading, setLoading] = useState(true);

  useEffect(() => {
    (async () => {
      try {
        const data = await request('GET', API.me);
        setUser(data.user);
        await refreshData();
        setView('dashboard');
      } catch (_err) {
        setUser(null);
        setView('dashboard');
      } finally {
        setLoading(false);
      }
    })();
  }, []);

  async function refreshData() {
    if (!user && !document.cookie.includes('token')) {
      return;
    }
    try {
      const [basesRes, categoriesRes, defensesRes] = await Promise.all([
        request('GET', API.bases),
        request('GET', API.categories),
        request('GET', API.defenses),
      ]);
      setBases(basesRes.bases || []);
      setCategories(categoriesRes.categories || []);
      setDefenses(defensesRes.defenses || []);
      setSummaries({
        overall: defensesRes.overall,
        categories: defensesRes.categories,
        bases: defensesRes.bases,
      });
    } catch (error) {
      console.error(error);
    }
  }

  const baseSummaryMap = useMemo(() => {
    const map = new Map<string, BaseSummary>();
    summaries?.bases.forEach((baseSummary) => map.set(baseSummary.baseId, baseSummary));
    return map;
  }, [summaries]);

  const categorySummaryMap = useMemo(() => {
    const map = new Map<string, CategorySummary>();
    summaries?.categories.forEach((categorySummary) => map.set(categorySummary.categoryId, categorySummary));
    return map;
  }, [summaries]);

  async function handleLogin(event: FormEvent<HTMLFormElement>) {
    event.preventDefault();
    const formData = new FormData(event.currentTarget);
    const payload = Object.fromEntries(formData.entries());
    try {
      setErrors((prev) => ({ ...prev, login: '' }));
      const data = await request('POST', API.login, payload);
      setUser(data.user);
      await refreshData();
      setView('dashboard');
    } catch (error: any) {
      setErrors((prev) => ({ ...prev, login: error.message }));
    }
  }

  async function handleSignup(event: FormEvent<HTMLFormElement>) {
    event.preventDefault();
    const formData = new FormData(event.currentTarget);
    const payload = Object.fromEntries(formData.entries());
    try {
      if ((payload.password as string)?.length < 6) {
        throw new Error('Use at least 6 characters for your password.');
      }
      setErrors((prev) => ({ ...prev, signup: '' }));
      const data = await request('POST', API.signup, payload);
      setUser(data.user);
      await refreshData();
      setView('dashboard');
    } catch (error: any) {
      setErrors((prev) => ({ ...prev, signup: error.message }));
    }
  }

  async function handleCategorySubmit(event: FormEvent<HTMLFormElement>) {
    event.preventDefault();
    const formData = new FormData(event.currentTarget);
    const payload = Object.fromEntries(formData.entries());
    try {
      setErrors((prev) => ({ ...prev, category: '' }));
      await request('POST', API.categories, payload);
      event.currentTarget.reset();
      await refreshData();
    } catch (error: any) {
      setErrors((prev) => ({ ...prev, category: error.message }));
    }
  }

  async function handleBaseSubmit(event: FormEvent<HTMLFormElement>) {
    event.preventDefault();
    const formData = new FormData(event.currentTarget);
    formData.set('imageMode', imageMode);
    if (imageMode === 'upload') {
      formData.delete('imageUrl');
    } else {
      formData.delete('imageFile');
    }
    try {
      setErrors((prev) => ({ ...prev, base: '' }));
      await request('POST', API.bases, formData, { isForm: true });
      event.currentTarget.reset();
      setImageMode('upload');
      await refreshData();
    } catch (error: any) {
      setErrors((prev) => ({ ...prev, base: error.message }));
    }
  }

  async function handleDefenseSubmit(event: FormEvent<HTMLFormElement>) {
    event.preventDefault();
    const formData = new FormData(event.currentTarget);
    const payload = Object.fromEntries(formData.entries());
    try {
      const baseId = payload.baseId as string;
      setErrors((prev) => ({ ...prev, defense: '' }));
      await request('POST', API.addDefense(baseId), payload);
      event.currentTarget.reset();
      await refreshData();
    } catch (error: any) {
      setErrors((prev) => ({ ...prev, defense: error.message }));
    }
  }

  async function handleLogout() {
    try {
      await request('POST', API.logout);
    } catch (error) {
      console.error(error);
    } finally {
      setUser(null);
      setBases([]);
      setCategories([]);
      setDefenses([]);
      setSummaries(null);
      setSelectedBaseId(null);
      setSelectedCategoryId(null);
      setView('dashboard');
    }
  }

  function openBaseDetail(baseId: string) {
    setSelectedBaseId(baseId);
    setView('baseDetail');
  }

  function openCategoryDetail(categoryId: string) {
    setSelectedCategoryId(categoryId);
    setView('categoryDetail');
  }

  const baseDetail = selectedBaseId ? baseSummaryMap.get(selectedBaseId) : null;
  const baseDetailMeta = selectedBaseId ? bases.find((base) => base.id === selectedBaseId) : null;
  const categoryDetail = selectedCategoryId ? categorySummaryMap.get(selectedCategoryId) : null;

  const categoryNameMap = useMemo(() => {
    const map = new Map<string, string>();
    categories.forEach((category) => map.set(category.id, category.name));
    return map;
  }, [categories]);

  function formatTrophies(value: number) {
    const sign = value > 0 ? '+' : '';
    return `${sign}${value} trophies`;
  }

  if (loading) {
    return (
      <main className="container">
        <section className="card">
          <h1>Loading Base Noter...</h1>
        </section>
      </main>
    );
  }

  if (!user) {
    return (
      <main className="container">
        <section id="auth-screen" className="card">
          <h1>Base Noter</h1>
          <p className="subtitle">Track how each base defends against every army.</p>
          <div className="tabs">
            <button
              className={`tab-button ${authTab === 'login' ? 'active' : ''}`}
              onClick={() => setAuthTab('login')}
            >
              Log In
            </button>
            <button
              className={`tab-button ${authTab === 'signup' ? 'active' : ''}`}
              onClick={() => setAuthTab('signup')}
            >
              Sign Up
            </button>
          </div>
          <div className="form-wrapper">
            {authTab === 'login' ? (
              <form className="form auth-form active" onSubmit={handleLogin}>
                <label>
                  Username
                  <input name="username" type="text" required autoComplete="username" />
                </label>
                <label>
                  Password
                  <input name="password" type="password" required />
                </label>
                <button type="submit" className="primary">
                  Log In
                </button>
                <p className="form-error" data-for="login">
                  {errors.login}
                </p>
              </form>
            ) : (
              <form className="form auth-form active" onSubmit={handleSignup}>
                <label>
                  Username
                  <input name="username" type="text" minLength={3} required autoComplete="username" />
                </label>
                <label>
                  Password
                  <input name="password" type="password" minLength={6} required autoComplete="new-password" />
                </label>
                <button type="submit" className="primary">
                  Create Account
                </button>
                <p className="form-error" data-for="signup">
                  {errors.signup}
                </p>
              </form>
            )}
          </div>
        </section>
      </main>
    );
  }

  return (
    <main className="container">
      <section id="app-screen">
        <header className="top-bar">
          <div>
            <h1>Base Noter</h1>
            <span id="user-username">{user.username}</span>
          </div>
          <div className="top-bar-actions">
            <button
              id="dashboard-button"
              className={`ghost ${view === 'dashboard' ? 'hidden' : ''}`}
              type="button"
              onClick={() => setView('dashboard')}
            >
              Dashboard
            </button>
            <button
              id="new-button"
              className={`ghost accent small ${view === 'forms' ? 'active' : ''}`}
              type="button"
              onClick={() => setView('forms')}
            >
              New Entry
            </button>
            <button id="logout-button" className="ghost" type="button" onClick={handleLogout}>
              Log Out
            </button>
          </div>
        </header>

        <section id="dashboard-view" className={`view-section ${view !== 'dashboard' ? 'hidden' : ''}`}>
          <section className="summary-grid">
            <div className="card">
              <h2>Overall Average</h2>
              <div className="stat" id="overall-summary">
                {summaries && summaries.overall.count ? (
                  <>
                    <strong>{summaries.overall.averageStars}★</strong> average •{' '}
                    <strong>{summaries.overall.averagePercent}%</strong> destruction
                    <br />
                    <span className="badge">{formatTrophies(summaries.overall.averageTrophies)}</span>{' '}
                    <span className="badge">{summaries.overall.count} attacks</span>
                  </>
                ) : (
                  'No defenses logged yet.'
                )}
              </div>
              <div className="subsection">
                <h3>Base Averages</h3>
                <ul id="base-summary" className="list compact">
                  {summaries && summaries.bases.length ? (
                    summaries.bases.map((base) => (
                      <li
                        key={base.baseId}
                        className="list-item clickable"
                        onClick={() => openBaseDetail(base.baseId)}
                      >
                        <div className="defense-header">
                          <strong>{base.title}</strong>
                          <span className="badge">{base.count} defenses</span>
                        </div>
                        <div className="defense-meta">
                          <span>{base.averageStars}★ avg</span>
                          <span>{base.averagePercent}% avg</span>
                          <span>{formatTrophies(base.averageTrophies)} avg</span>
                        </div>
                      </li>
                    ))
                  ) : (
                    <li>
                      {bases.length
                        ? 'Bases have defenses pending tracking.'
                        : 'Add a base to start collecting its averages.'}
                    </li>
                  )}
                </ul>
              </div>
            </div>
            <div className="card">
              <h2>Category Averages</h2>
              <ul id="category-summary" className="list">
                {summaries && summaries.categories.length ? (
                  summaries.categories.map((category) => (
                    <li
                      key={category.categoryId}
                      className="list-item clickable"
                      onClick={() => openCategoryDetail(category.categoryId)}
                    >
                      <div className="defense-header">
                        <strong>{category.name}</strong>
                        <span className="badge">{category.count} attacks</span>
                      </div>
                      <div className="defense-meta">
                        <span>{category.averageStars}★ avg</span>
                        <span>{category.averagePercent}% avg</span>
                        <span>{formatTrophies(category.averageTrophies)} avg</span>
                      </div>
                    </li>
                  ))
                ) : (
                  <li>Create an army category to start tracking.</li>
                )}
              </ul>
            </div>
          </section>

          <section className="card" id="defense-log-card">
            <h2>Defense Log</h2>
            <p className="subtitle">Newest entries appear on top.</p>
            <ul id="defense-list" className="list">
              {defenses.length ? (
                defenses.map((defense) => {
                  const date = new Date(defense.createdAt);
                  const categoryName = categoryNameMap.get(defense.armyCategoryId) || 'Unknown Army';
                  return (
                    <li key={defense.id} className="list-item">
                      <div className="defense-header">
                        <div>
                          <strong>{defense.baseTitle}</strong>
                          <span className="badge">{categoryName}</span>
                        </div>
                        <div>
                          <strong>{defense.stars}★</strong> • {defense.percent}% • {formatTrophies(defense.trophies)}
                        </div>
                      </div>
                      <div className="defense-meta">
                        <span>{date.toLocaleString()}</span>
                      </div>
                    </li>
                  );
                })
              ) : (
                <li>No defenses recorded yet.</li>
              )}
            </ul>
          </section>
        </section>

        <section id="forms-view" className={`forms-grid view-section ${view !== 'forms' ? 'hidden' : ''}`}>
          <div className="card">
            <h2>New Army Category</h2>
            <form id="category-form" className="form compact" onSubmit={handleCategorySubmit}>
              <label>
                Name
                <input type="text" name="name" required />
              </label>
              <button type="submit" className="primary">
                Add Category
              </button>
              <p className="form-error" data-for="category">
                {errors.category}
              </p>
            </form>
          </div>
          <div className="card">
            <h2>New Base</h2>
            <form id="base-form" className="form compact" onSubmit={handleBaseSubmit}>
              <label>
                Title
                <input type="text" name="title" required />
              </label>
              <label>
                Description
                <textarea name="description" rows={2}></textarea>
              </label>
              <label>
                Planning Link
                <input type="url" name="url" placeholder="https://" />
              </label>
              <div className="input-group">
                <span className="input-label">Image Source</span>
                <div className="image-mode">
                  <label>
                    <input
                      type="radio"
                      name="imageMode"
                      value="upload"
                      checked={imageMode === 'upload'}
                      onChange={() => setImageMode('upload')}
                    />
                    Upload
                  </label>
                  <label>
                    <input
                      type="radio"
                      name="imageMode"
                      value="url"
                      checked={imageMode === 'url'}
                      onChange={() => setImageMode('url')}
                    />
                    URL
                  </label>
                </div>
                {imageMode === 'upload' ? (
                  <input type="file" name="imageFile" accept="image/*" />
                ) : (
                  <input type="url" name="imageUrl" placeholder="https://" required />
                )}
              </div>
              <button type="submit" className="primary">
                Add Base
              </button>
              <p className="form-error" data-for="base">
                {errors.base}
              </p>
            </form>
          </div>
          <div className="card">
            <h2>Log Defense</h2>
            <form id="defense-form" className="form compact" onSubmit={handleDefenseSubmit}>
              <label>
                Base
                <select name="baseId" required defaultValue="">
                  <option value="" disabled>
                    {bases.length ? 'Select a base' : 'Add a base first'}
                  </option>
                  {bases.map((base) => (
                    <option key={base.id} value={base.id}>
                      {base.title}
                    </option>
                  ))}
                </select>
              </label>
              <label>
                Army Category
                <select name="armyCategoryId" required defaultValue="">
                  <option value="" disabled>
                    {categories.length ? 'Select an army category' : 'Add an army category first'}
                  </option>
                  {categories.map((category) => (
                    <option key={category.id} value={category.id}>
                      {category.name}
                    </option>
                  ))}
                </select>
              </label>
              <label>
                Stars
                <input type="number" name="stars" min={0} max={3} step={1} required className="styled-number" />
              </label>
              <label>
                Destruction %
                <input type="number" name="percent" min={0} max={100} step={1} required className="styled-number" />
              </label>
              <label>
                Trophies ±
                <input
                  type="number"
                  name="trophies"
                  min={-200}
                  max={200}
                  step={1}
                  defaultValue={0}
                  required
                  className="styled-number"
                />
              </label>
              <button type="submit" className="primary">
                Record Defense
              </button>
              <p className="form-error" data-for="defense">
                {errors.defense}
              </p>
            </form>
          </div>
        </section>

        <section id="base-detail-view" className={`view-section ${view !== 'baseDetail' ? 'hidden' : ''}`}>
          <div className="card">
            <div className="detail-header">
              <button className="ghost" type="button" onClick={() => setView('dashboard')}>
                Back
              </button>
              <span id="base-detail-created" className="detail-created">
                {baseDetailMeta ? `Created ${new Date(baseDetailMeta.createdAt).toLocaleString()}` : ''}
              </span>
            </div>
            <h2 id="base-detail-title">{baseDetailMeta?.title}</h2>
            <p id="base-detail-description" className={baseDetailMeta?.description ? '' : 'muted'}>
              {baseDetailMeta?.description || 'No description yet.'}
            </p>
            <div id="base-detail-links" className={`detail-links ${baseDetailMeta?.url ? '' : 'hidden'}`}>
              {baseDetailMeta?.url && (
                <a href={baseDetailMeta.url} target="_blank" rel="noopener noreferrer">
                  Open planning link
                </a>
              )}
            </div>
            <div
              id="base-detail-image-wrapper"
              className={`detail-image ${baseDetailMeta?.imageUrl ? '' : 'hidden'}`}
            >
              {baseDetailMeta?.imageUrl && (
                // eslint-disable-next-line @next/next/no-img-element
                <img src={baseDetailMeta.imageUrl} alt={`Preview of ${baseDetailMeta.title}`} />
              )}
            </div>
          </div>
          <div className="card">
            <h3>Base Averages</h3>
            <div id="base-detail-stats" className="stat">
              {baseDetail && baseDetail.count ? (
                <>
                  <strong>{baseDetail.averageStars}★</strong> average •{' '}
                  <strong>{baseDetail.averagePercent}%</strong> destruction
                  <br />
                  <span className="badge">{formatTrophies(baseDetail.averageTrophies)} avg</span>{' '}
                  <span className="badge">{baseDetail.count} defenses</span>
                </>
              ) : (
                'No defenses logged yet.'
              )}
            </div>
          </div>
          <div className="card">
            <h3>Army Categories vs This Base</h3>
            <ul id="base-detail-categories" className="list">
              {baseDetail && baseDetail.categories.length ? (
                baseDetail.categories.map((category) => (
                  <li
                    key={category.categoryId}
                    className="list-item clickable"
                    onClick={() => openCategoryDetail(category.categoryId)}
                  >
                    <div className="defense-header">
                      <strong>{category.name}</strong>
                      <span className="badge">{category.count} attacks</span>
                    </div>
                    <div className="defense-meta">
                      <span>{category.averageStars}★ avg</span>
                      <span>{category.averagePercent}% avg</span>
                      <span>{formatTrophies(category.averageTrophies)} avg</span>
                    </div>
                  </li>
                ))
              ) : (
                <li>No army categories have attacked this base yet.</li>
              )}
            </ul>
          </div>
          <div className="card">
            <h3>Defenses</h3>
            <ul id="base-detail-defenses" className="list">
              {defenses.filter((defense) => defense.baseId === selectedBaseId).length ? (
                defenses
                  .filter((defense) => defense.baseId === selectedBaseId)
                  .map((defense) => {
                    const date = new Date(defense.createdAt);
                    const categoryName = categoryNameMap.get(defense.armyCategoryId) || 'Unknown Army';
                    return (
                      <li key={defense.id} className="list-item">
                        <div className="defense-header">
                          <strong>{categoryName}</strong>
                          <div>
                            <strong>{defense.stars}★</strong> • {defense.percent}% • {formatTrophies(defense.trophies)}
                          </div>
                        </div>
                        <div className="defense-meta">
                          <span>{date.toLocaleString()}</span>
                        </div>
                      </li>
                    );
                  })
              ) : (
                <li>No defenses recorded for this base yet.</li>
              )}
            </ul>
          </div>
        </section>

        <section id="category-detail-view" className={`view-section ${view !== 'categoryDetail' ? 'hidden' : ''}`}>
          <div className="card">
            <div className="detail-header">
              <button className="ghost" type="button" onClick={() => setView('dashboard')}>
                Back
              </button>
            </div>
            <h2 id="category-detail-title">{categoryDetail?.name}</h2>
            <p id="category-detail-description" className="muted">
              Average performance of this army across your bases.
            </p>
          </div>
          <div className="card">
            <h3>Category Averages</h3>
            <div id="category-detail-stats" className="stat">
              {categoryDetail && categoryDetail.count ? (
                <>
                  <strong>{categoryDetail.averageStars}★</strong> average •{' '}
                  <strong>{categoryDetail.averagePercent}%</strong> destruction
                  <br />
                  <span className="badge">{formatTrophies(categoryDetail.averageTrophies)} avg</span>{' '}
                  <span className="badge">{categoryDetail.count} attacks</span>
                </>
              ) : (
                'No defenses logged yet.'
              )}
            </div>
          </div>
          <div className="card">
            <h3>Performance by Base</h3>
            <ul id="category-detail-bases" className="list">
              {categoryDetail && categoryDetail.bases.length ? (
                categoryDetail.bases.map((base) => (
                  <li
                    key={base.baseId}
                    className="list-item clickable"
                    onClick={() => openBaseDetail(base.baseId)}
                  >
                    <div className="defense-header">
                      <strong>{base.title}</strong>
                      <span className="badge">{base.count} defenses</span>
                    </div>
                    <div className="defense-meta">
                      <span>{base.averageStars}★ avg</span>
                      <span>{base.averagePercent}% avg</span>
                      <span>{formatTrophies(base.averageTrophies)} avg</span>
                    </div>
                  </li>
                ))
              ) : (
                <li>This army has not attacked any bases yet.</li>
              )}
            </ul>
          </div>
          <div className="card">
            <h3>Defenses</h3>
            <ul id="category-detail-defenses" className="list">
              {defenses.filter((defense) => defense.armyCategoryId === selectedCategoryId).length ? (
                defenses
                  .filter((defense) => defense.armyCategoryId === selectedCategoryId)
                  .map((defense) => {
                    const date = new Date(defense.createdAt);
                    return (
                      <li key={defense.id} className="list-item">
                        <div className="defense-header">
                          <strong>{defense.baseTitle}</strong>
                          <div>
                            <strong>{defense.stars}★</strong> • {defense.percent}% • {formatTrophies(defense.trophies)}
                          </div>
                        </div>
                        <div className="defense-meta">
                          <span>{date.toLocaleString()}</span>
                        </div>
                      </li>
                    );
                  })
              ) : (
                <li>No logged defenses for this army yet.</li>
              )}
            </ul>
          </div>
        </section>
      </section>
    </main>
  );
}
