import { Hono } from 'hono';
import type { Context } from 'hono';
import type { Env } from '../env';
import { getSettings } from '../services/settings';
import { listPosts, getPost } from '../services/posts';
import { listComments } from '../services/comments';
import { listPublicLinks } from '../services/links';
import { mediaUrl } from '../utils/image';
import { first } from '../db/queries';
import { HomePage } from '../views/home';
import { PostDetailPage } from '../views/post-detail';
import { LoginPage } from '../views/login';
import { RegisterPage } from '../views/register';
import { UserPage } from '../views/user';
import { LinksPage, MessagePage } from '../views/simple';

export const pages = new Hono<Env>();

async function common(c: Context<Env>) {
  const settings = await getSettings(c.env);
  const links = await listPublicLinks(c.env, settings);
  return { settings, links, currentUser: c.get('currentUser'), csrfToken: c.get('csrfToken') };
}

async function commentsForPosts(env: Env['Bindings'], postIds: string[], viewer: Env['Variables']['currentUser']) {
  const entries = await Promise.all(postIds.map(async (id) => [id, await listComments(env, id, viewer)] as const));
  return new Map(entries);
}

pages.get('/', async (c) => {
  const ctx = await common(c);
  const result = await listPosts(c.env, ctx.settings, { viewer: ctx.currentUser, limit: 20 });
  const commentsByPost = await commentsForPosts(c.env, result.posts.map((post) => post.id), ctx.currentUser);
  return c.html(
    <HomePage
      settings={ctx.settings}
      currentUser={ctx.currentUser}
      csrfToken={ctx.csrfToken}
      posts={result.posts}
      commentsByPost={commentsByPost}
      nextCursor={result.nextCursor}
      links={ctx.links}
    />
  );
});

pages.get('/p/:id', async (c) => {
  const ctx = await common(c);
  const post = await getPost(c.env, ctx.settings, c.req.param('id'), ctx.currentUser);
  if (!post) return c.notFound();
  const comments = await listComments(c.env, post.id, ctx.currentUser);
  return c.html(<PostDetailPage settings={ctx.settings} currentUser={ctx.currentUser} csrfToken={ctx.csrfToken} post={post} comments={comments} links={ctx.links} />);
});

pages.get('/u/:username', async (c) => {
  const ctx = await common(c);
  const profile = await first<{ username: string; display_name: string; avatar_key: string | null; bio: string; url: string }>(
    c.env.DB.prepare('SELECT username, display_name, avatar_key, bio, url FROM wm_users WHERE username = ? AND status = "active"').bind(c.req.param('username'))
  );
  if (!profile) return c.notFound();
  const result = await listPosts(c.env, ctx.settings, { viewer: ctx.currentUser, authorUsername: profile.username, limit: 20 });
  const commentsByPost = await commentsForPosts(c.env, result.posts.map((post) => post.id), ctx.currentUser);
  return c.html(
    <UserPage
      profile={{ username: profile.username, displayName: profile.display_name, avatarKey: profile.avatar_key, bio: profile.bio || '', url: profile.url || '' }}
      settings={ctx.settings}
      currentUser={ctx.currentUser}
      csrfToken={ctx.csrfToken}
      posts={result.posts}
      commentsByPost={commentsByPost}
      links={ctx.links}
    />
  );
});

pages.get('/login', async (c) => {
  const ctx = await common(c);
  return c.html(<LoginPage settings={ctx.settings} currentUser={ctx.currentUser} csrfToken={ctx.csrfToken} links={ctx.links} />);
});

pages.get('/register', async (c) => {
  const ctx = await common(c);
  return c.html(<RegisterPage settings={ctx.settings} currentUser={ctx.currentUser} csrfToken={ctx.csrfToken} links={ctx.links} />);
});

pages.get('/forgot', async (c) => {
  const ctx = await common(c);
  return c.html(<MessagePage title="找回密码" message="找回密码接口已预留，v1 会将重置邮件输出到日志。" settings={ctx.settings} currentUser={ctx.currentUser} csrfToken={ctx.csrfToken} links={ctx.links} />);
});

pages.get('/links', async (c) => {
  const ctx = await common(c);
  return c.html(<LinksPage settings={ctx.settings} currentUser={ctx.currentUser} csrfToken={ctx.csrfToken} links={ctx.links} />);
});

pages.get('/search', async (c) => {
  const ctx = await common(c);
  const q = c.req.query('q') || '';
  const result = await listPosts(c.env, ctx.settings, { viewer: ctx.currentUser, q, limit: 20 });
  const commentsByPost = await commentsForPosts(c.env, result.posts.map((post) => post.id), ctx.currentUser);
  return c.html(
    <HomePage
      title={q ? `搜索：${q}` : '搜索'}
      settings={ctx.settings}
      currentUser={ctx.currentUser}
      csrfToken={ctx.csrfToken}
      posts={result.posts}
      commentsByPost={commentsByPost}
      nextCursor={result.nextCursor}
      links={ctx.links}
    />
  );
});

pages.get('/r2/*', async (c) => {
  const settings = await getSettings(c.env);
  const key = decodeURIComponent(c.req.path.replace(/^\/r2\//, ''));
  if (!key) return c.notFound();
  if (settings.cdn_base_url) return c.redirect(mediaUrl(settings.cdn_base_url, key, ''), 301);
  const object = await c.env.R2.get(key);
  if (!object) return c.notFound();
  const headers = new Headers();
  object.writeHttpMetadata(headers);
  headers.set('ETag', object.httpEtag);
  headers.set('Cache-Control', 'public, max-age=31536000, immutable');
  return new Response(object.body, { headers });
});

pages.get('/robots.txt', (c) => c.text('User-agent: *\nAllow: /\n'));

pages.get('/assets/*', (c) => c.env.ASSETS.fetch(c.req.raw));
