import * as path from 'path';
import React from 'react';
import express from 'express';
import { Provider } from 'react-redux';
import { applyMiddleware, createStore } from 'redux';
import thunk from 'redux-thunk';
import { StaticRouter } from 'react-router-dom';
import { renderToString } from 'react-dom/server';

import { app as api } from './api';
import { render } from './page';
import { registry } from './registry';
import { reducers, ApplicationState } from '../common/entities';
import { App } from '../common/pages/app/app';
import { DispatchLock, DispatchMonitor } from '../common/utils';

const app = express();

app.use('/api', api);
app.use('/dist', express.static(path.join(process.cwd(), '.compiled', 'dist')));

app.get('*', async (req, res, next) => {
  // First-pass render
  const monitor = new DispatchMonitor();
  const initialStore = createStore(
    reducers,
    applyMiddleware(
      monitor.getMiddleware(), // always needs to be before thunk;
      thunk.withExtraArgument(registry),
    ),
  );
  const initialHtml = renderToString(
    <Provider store={initialStore}>
      <StaticRouter location={req.url}>
        <App />
      </StaticRouter>
    </Provider>,
  );

  const state = (await monitor.wait()) as ApplicationState;

  // Second-pass render
  const lock = new DispatchLock();
  const finalStore = createStore(
    reducers,
    state,
    applyMiddleware(lock.getMiddleware(), thunk.withExtraArgument(registry)),
  );
  const finalHtml = renderToString(
    <Provider store={finalStore}>
      <StaticRouter location={req.url}>
        <App />
      </StaticRouter>
    </Provider>,
  );

  res.status(200).send(render(state, finalHtml));
});

app.listen(3000, () => {
  console.log('listening on 3000 ... ');
});
