import type { NodeOAuthClient } from '@atproto/oauth-client-node'
import { createLogger } from '@wispplace/observability'
import { PRIVATE_ACCESS_PAGE_STYLES } from '@wispplace/private-sites'
import { Elysia } from 'elysia'
import { authorizeWisp } from '../lib/oauth-authorize'
import { openPrivateSiteForAccount, redeemScopedShare, resolveShareLink } from '../lib/private-sites-service'
import { authenticateRequest, SESSION_COOKIE_NAME } from '../lib/wisp-auth'

const logger = createLogger('main-app')
const json = (value: unknown): string =>
	JSON.stringify(value).replace(/</g, '\\u003c').replace(/>/g, '\\u003e').replace(/&/g, '\\u0026')

const page = (title: string, body: string): string => `<!doctype html>
<html lang="en"><head><meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta name="robots" content="noindex, nofollow">
<title>${title} — wisp.place</title>
<style>${PRIVATE_ACCESS_PAGE_STYLES}</style></head>
<body><main class="private-page private-shell">${body}</main></body></html>`

const signInPage = (siteId: string, token?: string): string => {
	const shared = token !== undefined
	return page(
		'sign in',
		`<div class="private-brand"><strong>wisp.place</strong></div>
${shared ? '<p class="private-kicker">shared link</p>' : ''}
<h1>sign in to open this ${shared ? 'link' : 'private site'}</h1>
${shared ? '' : '<p>only accounts with access can open it without a share link.</p>'}
<form id="f" class="private-form">
 <label for="handle">your handle</label>
 <input type="text" id="handle" placeholder="alice.bsky.social" autocomplete="username" autocapitalize="none" autocorrect="off" required>
 <button class="private-action" id="action" type="submit" disabled>sign in to continue <span aria-hidden="true">→</span></button>
 <p class="private-error" id="err" aria-live="polite"></p>
</form>
<script>
 var payload = ${json({ siteId, token })}
 var form = document.getElementById('f'), input = document.getElementById('handle'), action = document.getElementById('action'), error = document.getElementById('err')
 function sync() { action.disabled = !input.value.trim() || action.getAttribute('aria-busy') === 'true' }
 input.addEventListener('input', sync)
 form.addEventListener('submit', function (event) {
   event.preventDefault()
   if (!input.value.trim() || action.getAttribute('aria-busy') === 'true') return
   action.setAttribute('aria-busy', 'true'); sync(); error.textContent = ''
   fetch('/private/sign-in', {
     method: 'POST', headers: { 'content-type': 'application/json' },
     body: JSON.stringify(Object.assign({ handle: input.value.trim() }, payload))
   }).then(function (r) { return r.json() }).then(function (result) {
     if (result.url) location.href = result.url
     else error.textContent = 'could not start sign-in for that handle.'
   }).catch(function () { error.textContent = 'could not start sign-in.' }).finally(function () {
     action.removeAttribute('aria-busy'); sync()
   })
 })
</script>`,
	)
}

const deniedPage = (): string =>
	page(
		'not available',
		`<div class="private-brand"><strong>wisp.place</strong></div>
<h1>this link is not available</h1>
<p>it may have been revoked, expired, or issued to a different account.</p>`,
	)

const htmlResponse = (set: { headers: Record<string, string | number>; status?: number | string }, body: string) => {
	set.headers['Content-Type'] = 'text/html; charset=utf-8'
	set.headers['Cache-Control'] = 'no-store, no-cache, must-revalidate, private'
	set.headers['Referrer-Policy'] = 'no-referrer'
	set.headers['X-Robots-Tag'] = 'noindex, nofollow'
	return body
}

const readBody = (body: unknown) => {
	const value = body as { siteId?: unknown; token?: unknown; handle?: unknown } | null
	return {
		siteId: typeof value?.siteId === 'string' ? value.siteId : '',
		token: typeof value?.token === 'string' ? value.token : undefined,
		handle: typeof value?.handle === 'string' ? value.handle.trim() : '',
	}
}

export const resolvePrivateShareState = async (
	state: string | null | undefined,
	viewerDid: string,
): Promise<{ url: string | null } | null> => {
	if (!state) return null
	let parsed: { kind?: unknown; siteId?: unknown; token?: unknown }
	try {
		parsed = JSON.parse(state)
	} catch {
		return null
	}
	if (typeof parsed.siteId !== 'string') return null
	if (parsed.kind === 'privateOpen') return { url: await openPrivateSiteForAccount(parsed.siteId, viewerDid) }
	if (parsed.kind !== 'privateShare' || typeof parsed.token !== 'string') return null
	return { url: await redeemScopedShare(parsed.siteId, parsed.token, viewerDid) }
}

export const privateRedeemRoutes = (client: NodeOAuthClient, cookieSecret: string) =>
	new Elysia({ cookie: { secrets: cookieSecret, sign: [SESSION_COOKIE_NAME] } })
		.post('/private/redeem', async ({ body, cookie, request, set }) => {
			const { siteId, token } = readBody(body)
			if (!siteId || !token) {
				set.status = 400
				return htmlResponse(set, deniedPage())
			}
			const auth = await authenticateRequest(client, cookie, request.headers.get('cookie'))
			if (!auth) return htmlResponse(set, signInPage(siteId, token))
			const url = await redeemScopedShare(siteId, token, auth.did)
			if (!url) {
				set.status = 404
				return htmlResponse(set, deniedPage())
			}
			set.status = 303
			set.headers.Location = url
			return ''
		})
		.get('/private/denied', ({ set }) => {
			set.status = 403
			return htmlResponse(set, deniedPage())
		})
		.get('/private/open', async ({ query, cookie, request, set }) => {
			const siteId = typeof query.siteId === 'string' ? query.siteId : ''
			if (!siteId) {
				set.status = 400
				return htmlResponse(set, deniedPage())
			}
			const auth = await authenticateRequest(client, cookie, request.headers.get('cookie'))
			if (!auth) return htmlResponse(set, signInPage(siteId))
			const url = await openPrivateSiteForAccount(siteId, auth.did)
			if (!url) {
				set.status = 404
				return htmlResponse(set, deniedPage())
			}
			set.status = 303
			set.headers.Location = url
			return ''
		})
		.get('/p/:token', async ({ params, set }) => {
			const target = await resolveShareLink(params.token ?? '')
			if (!target) {
				set.status = 404
				return htmlResponse(set, deniedPage())
			}
			set.status = 302
			set.headers.Location = target
			set.headers['Cache-Control'] = 'no-store, no-cache, must-revalidate, private'
			set.headers['Referrer-Policy'] = 'no-referrer'
			return ''
		})
		.post('/private/sign-in', async ({ body, set }) => {
			const { siteId, token, handle } = readBody(body)
			if (!siteId || !handle) {
				set.status = 400
				return { error: 'missing handle' }
			}
			try {
				const state = JSON.stringify({ kind: token ? 'privateShare' : 'privateOpen', siteId, token })
				return { url: (await authorizeWisp(client, handle, { state })).toString() }
			} catch (err) {
				logger.error('[PrivateSite] Sign-in failed', err)
				set.status = 400
				return { error: 'sign-in unavailable' }
			}
		})
