import React, { useState, useEffect, useRef } from 'react';
import axios from 'axios';
import './App.css';

const API_URL = '/api';

function App() {
  const [isAuthenticated, setIsAuthenticated] = useState(false);
  const [isLogin, setIsLogin] = useState(true);
  const [username, setUsername] = useState('');
  const [password, setPassword] = useState('');
  const [error, setError] = useState('');
  const [loading, setLoading] = useState(false);
  const [stocks, setStocks] = useState([]);
  const [instanceInfo, setInstanceInfo] = useState('');
  const [currentUser, setCurrentUser] = useState('');
  const refreshingToken = useRef(false);

  useEffect(() => {
    const accessToken = localStorage.getItem('accessToken');
    const user = localStorage.getItem('username');
    if (accessToken && user) {
      setIsAuthenticated(true);
      setCurrentUser(user);
      fetchStocks(accessToken);
    }
  }, []);

  // Auto-refresh effect - only runs when authenticated
  useEffect(() => {
    if (!isAuthenticated) return;

    const accessToken = localStorage.getItem('accessToken');
    if (!accessToken) return;

    // Auto-refresh stock data every 1 second for real-time updates
    const intervalId = setInterval(() => {
      fetchStocks(accessToken);
    }, 1000);

    // Cleanup interval on unmount or when logged out
    return () => clearInterval(intervalId);
  }, [isAuthenticated]);

  // Function to refresh access token
  const refreshToken = async () => {
    if (refreshingToken.current) {
      // Already refreshing, wait a bit and retry
      await new Promise(resolve => setTimeout(resolve, 100));
      return localStorage.getItem('accessToken');
    }

    refreshingToken.current = true;
    try {
      const refreshTokenValue = localStorage.getItem('refreshToken');
      if (!refreshTokenValue) {
        throw new Error('No refresh token available');
      }

      const response = await axios.post(`${API_URL}/auth/refresh`, {
        refreshToken: refreshTokenValue,
      });

      localStorage.setItem('accessToken', response.data.accessToken);
      refreshingToken.current = false;
      return response.data.accessToken;
    } catch (err) {
      refreshingToken.current = false;
      handleLogout();
      throw err;
    }
  };

  const handleAuth = async (e) => {
    e.preventDefault();
    setError('');
    setLoading(true);

    try {
      const endpoint = isLogin ? '/auth/login' : '/auth/register';
      const response = await axios.post(`${API_URL}${endpoint}`, {
        username,
        password,
      });

      localStorage.setItem('accessToken', response.data.accessToken);
      localStorage.setItem('refreshToken', response.data.refreshToken);
      localStorage.setItem('username', response.data.user.username);
      setIsAuthenticated(true);
      setCurrentUser(response.data.user.username);
      setInstanceInfo(response.data.instance);
      fetchStocks(response.data.accessToken);
    } catch (err) {
      setError(err.response?.data?.error || 'Authentication failed');
    } finally {
      setLoading(false);
    }
  };

  const fetchStocks = async (token = null) => {
    setLoading(true);
    try {
      const authToken = token || localStorage.getItem('accessToken');
      const response = await axios.get(`${API_URL}/stocks`, {
        headers: {
          Authorization: `Bearer ${authToken}`,
        },
      });

      setStocks(response.data.stocks);
      setInstanceInfo(response.data.instance);
    } catch (err) {
      if (err.response?.status === 401 && err.response?.data?.code === 'TOKEN_EXPIRED') {
        // Token expired, try to refresh
        try {
          const newToken = await refreshToken();
          // Retry the request with new token
          const response = await axios.get(`${API_URL}/stocks`, {
            headers: {
              Authorization: `Bearer ${newToken}`,
            },
          });
          setStocks(response.data.stocks);
          setInstanceInfo(response.data.instance);
        } catch (refreshErr) {
          handleLogout();
        }
      } else if (err.response?.status === 401) {
        handleLogout();
      } else {
        setError('Failed to fetch stock data');
      }
    } finally {
      setLoading(false);
    }
  };

  const handleLogout = async () => {
    try {
      const refreshTokenValue = localStorage.getItem('refreshToken');
      if (refreshTokenValue) {
        await axios.post(`${API_URL}/auth/logout`, {
          refreshToken: refreshTokenValue,
        });
      }
    } catch (err) {
      console.error('Logout error:', err);
    } finally {
      localStorage.removeItem('accessToken');
      localStorage.removeItem('refreshToken');
      localStorage.removeItem('username');
      setIsAuthenticated(false);
      setCurrentUser('');
      setStocks([]);
      setInstanceInfo('');
    }
  };

  const formatPrice = (price) => {
    return new Intl.NumberFormat('en-US', {
      style: 'currency',
      currency: 'USD',
    }).format(price);
  };

  const formatTime = (timestamp) => {
    return new Date(timestamp).toLocaleTimeString();
  };

  if (!isAuthenticated) {
    return (
      <div className='App'>
        <div className='auth-container'>
          <h2>{isLogin ? 'Login' : 'Register'}</h2>
          {error && <div className='error-message'>{error}</div>}
          <form className='auth-form' onSubmit={handleAuth}>
            <div className='form-group'>
              <label>Username</label>
              <input
                type='text'
                value={username}
                onChange={(e) => setUsername(e.target.value)}
                required
                disabled={loading}
              />
            </div>
            <div className='form-group'>
              <label>Password</label>
              <input
                type='password'
                value={password}
                onChange={(e) => setPassword(e.target.value)}
                required
                minLength='6'
                disabled={loading}
              />
            </div>
            <button type='submit' className='submit-btn' disabled={loading}>
              {loading ? 'Processing...' : isLogin ? 'Login' : 'Register'}
            </button>
          </form>
          <div className='toggle-auth'>
            {isLogin ? "Don't have an account? " : 'Already have an account? '}
            <button
              onClick={() => {
                setIsLogin(!isLogin);
                setError('');
              }}
            >
              {isLogin ? 'Register' : 'Login'}
            </button>
          </div>
        </div>
      </div>
    );
  }

  return (
    <div className='App'>
      <div className='container'>
        <div className='header'>
          <h1>📈 Distributed Stock Provider</h1>
          <div className='status-bar'>
            <div className='instance-info'>
              🖥️ Instance: {instanceInfo || 'Loading...'}
            </div>
            <div className='user-info'>
              <span>👤 {currentUser}</span>
              <button
                className='refresh-btn'
                onClick={() => fetchStocks()}
                disabled={loading}
              >
                🔄 Refresh
              </button>
              <button className='logout-btn' onClick={handleLogout}>
                Logout
              </button>
            </div>
          </div>
        </div>

        {loading && stocks.length === 0 ? (
          <div className='loading'>Loading stock data...</div>
        ) : (
          <div className='stocks-grid'>
            {stocks.map((stock) => (
              <div key={stock.symbol} className='stock-card'>
                <div className='stock-symbol'>{stock.symbol}</div>
                <div className='stock-price'>{formatPrice(stock.price)}</div>
                <div
                  className={`stock-change ${stock.changePercent >= 0 ? 'positive' : 'negative'}`}
                >
                  {stock.changePercent >= 0 ? '▲' : '▼'}{' '}
                  {Math.abs(stock.changePercent).toFixed(2)}%
                </div>
                <div className='stock-updated'>
                  Updated: {formatTime(stock.lastUpdated)}
                </div>
              </div>
            ))}
          </div>
        )}
      </div>
    </div>
  );
}

export default App;

// Made with Bob
