import { Body, Controller, Get, Header, Post, Query, Res } from '@nestjs/common';
import { ConfigService } from '@nestjs/config';
import { ApiExcludeController } from '@nestjs/swagger';
import { Response } from 'express';
import { apiPath, consoleLoginPath, docsPath as apiDocsPath, sandboxPath as apiSandboxPath, versionedApiPath } from '../common/api-paths';
import { AuthService } from './auth.service';
import { AuthThrottle } from './auth-throttle.decorator';
import { Public } from './public.decorator';

type ConsoleLoginBody = {
  phone?: string;
  otp?: string;
  returnTo?: string;
};

@Public()
@ApiExcludeController()
@Controller({ path: 'console', version: '1' })
export class ConsoleController {
  private readonly cookieName = 'smart_estate_console_token';

  constructor(
    private readonly auth: AuthService,
    private readonly config: ConfigService
  ) {}

  @Get('login')
  @Header('Content-Type', 'text/html; charset=utf-8')
  loginPage(
    @Query('returnTo') returnTo = '',
    @Query('phone') phone = '',
    @Query('notice') notice?: string,
    @Query('devOtp') devOtp?: string,
    @Query('error') error?: string
  ) {
    const safeReturnTo = this.safeReturnTo(returnTo || this.docsPath());
    const errorBlock = error ? `<div class="error">${this.escape(error)}</div>` : '';
    const noticeBlock = notice ? `<div class="notice">${this.escape(notice)}${devOtp ? ` DEV OTP: ${this.escape(devOtp)}` : ''}</div>` : '';
    return `<!doctype html>
<html lang="en">
<head>
  <meta charset="utf-8" />
  <meta name="viewport" content="width=device-width, initial-scale=1" />
  <title>Super Admin Console Login</title>
  <style>
    :root { color-scheme: light; --bg: #f6f8fb; --panel: #fff; --ink: #172033; --muted: #607086; --line: #d9e1ec; --accent: #0f766e; --danger: #b42318; }
    * { box-sizing: border-box; }
    body { margin: 0; min-height: 100vh; display: grid; place-items: center; background: var(--bg); color: var(--ink); font-family: Inter, ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif; }
    main { width: min(420px, calc(100vw - 32px)); background: var(--panel); border: 1px solid var(--line); border-radius: 8px; padding: 24px; }
    h1 { margin: 0 0 8px; font-size: 24px; letter-spacing: 0; }
    p { margin: 0 0 18px; color: var(--muted); line-height: 1.5; }
    label { display: block; margin: 14px 0 6px; font-weight: 700; font-size: 13px; }
    input { width: 100%; border: 1px solid var(--line); border-radius: 6px; padding: 11px 12px; font: inherit; }
    button { width: 100%; margin-top: 18px; border: 0; border-radius: 6px; padding: 12px; font: inherit; font-weight: 800; color: #fff; background: var(--accent); cursor: pointer; }
    .error { margin: 0 0 14px; padding: 10px 12px; border-radius: 6px; color: var(--danger); background: #fff1f0; border: 1px solid #ffd0cc; }
    .notice { margin: 0 0 14px; padding: 10px 12px; border-radius: 6px; color: #0b5f59; background: #ecfdf5; border: 1px solid #b8eadc; }
    .secondary { background: #e8eef6; color: var(--ink); }
  </style>
</head>
<body>
  <main>
    <h1>Super Admin Console</h1>
    <p>Sign in as a super admin to open Swagger docs or the API sandbox.</p>
    ${errorBlock}
    ${noticeBlock}
    <form method="post" action="${this.consolePath('request-otp')}">
      <input type="hidden" name="returnTo" value="${this.escape(safeReturnTo)}" />
      <label for="requestPhone">Phone</label>
      <input id="requestPhone" name="phone" type="tel" autocomplete="username" value="${this.escape(phone)}" placeholder="+2348000000001" required />
      <button class="secondary" type="submit">Send OTP</button>
    </form>
    <form method="post" action="${this.consolePath('login')}">
      <input type="hidden" name="returnTo" value="${this.escape(safeReturnTo)}" />
      <label for="phone">Phone</label>
      <input id="phone" name="phone" type="tel" autocomplete="username" value="${this.escape(phone)}" placeholder="+2348000000001" required />
      <label for="otp">OTP</label>
      <input id="otp" name="otp" inputmode="numeric" autocomplete="one-time-code" placeholder="123456" required />
      <button type="submit">Continue</button>
    </form>
  </main>
</body>
</html>`;
  }

  @Post('request-otp')
  @AuthThrottle()
  async requestOtp(@Body() body: ConsoleLoginBody, @Res() res: Response) {
    const returnTo = this.safeReturnTo(body.returnTo ?? this.docsPath());
    const phone = body.phone ?? '';
    try {
      const result = await this.auth.requestConsoleOtp(phone);
      const query = new URLSearchParams({
        returnTo,
        phone,
        notice: 'OTP sent'
      });
      if (result.devOtp) {
        query.set('devOtp', result.devOtp);
      }
      return res.redirect(`${this.loginPath()}?${query.toString()}`);
    } catch (error) {
      const message = error instanceof Error ? error.message : 'OTP request failed';
      return res.redirect(
        `${this.loginPath()}?returnTo=${encodeURIComponent(returnTo)}&phone=${encodeURIComponent(phone)}&error=${encodeURIComponent(message)}`
      );
    }
  }

  @Post('login')
  @AuthThrottle()
  async login(@Body() body: ConsoleLoginBody, @Res() res: Response) {
    const returnTo = this.safeReturnTo(body.returnTo ?? this.docsPath());
    try {
      const token = await this.auth.issueConsoleSession({
        phone: body.phone ?? '',
        otp: body.otp ?? ''
      });
      res.cookie(this.cookieName, token, {
        httpOnly: true,
        sameSite: 'lax',
        secure: this.config.get<string>('NODE_ENV') === 'production',
        maxAge: this.consoleSessionMaxAge(),
        path: apiPath(this.config)
      });
      return res.redirect(returnTo);
    } catch (error) {
      const message = error instanceof Error ? error.message : 'Console login failed';
      return res.redirect(`${this.loginPath()}?returnTo=${encodeURIComponent(returnTo)}&error=${encodeURIComponent(message)}`);
    }
  }

  @Post('logout')
  logout(@Res() res: Response) {
    res.clearCookie(this.cookieName, { path: apiPath(this.config) });
    return res.redirect(this.loginPath());
  }

  private safeReturnTo(value: string) {
    if (!value.startsWith(this.docsPath()) && !value.startsWith(apiSandboxPath(this.config))) {
      return this.docsPath();
    }
    return value;
  }

  private docsPath() {
    return apiDocsPath(this.config);
  }

  private loginPath() {
    return consoleLoginPath(this.config);
  }

  private consolePath(action: string) {
    return versionedApiPath(this.config, 'console', action);
  }

  private consoleSessionMaxAge() {
    const ttl = this.config.get<string>('CONSOLE_SESSION_TTL', '8h');
    const hours = ttl.match(/^(\d+)h$/i);
    if (hours) {
      return Number(hours[1]) * 60 * 60 * 1000;
    }
    const seconds = ttl.match(/^(\d+)s$/i);
    if (seconds) {
      return Number(seconds[1]) * 1000;
    }
    return 8 * 60 * 60 * 1000;
  }

  private escape(value: string) {
    return value
      .replaceAll('&', '&amp;')
      .replaceAll('<', '&lt;')
      .replaceAll('>', '&gt;')
      .replaceAll('"', '&quot;')
      .replaceAll("'", '&#039;');
  }
}
