/** Cloudflare Worker entry point for the vinext-starter template. */
import { handleImageOptimization, DEFAULT_DEVICE_SIZES, DEFAULT_IMAGE_SIZES } from "vinext/server/image-optimization";
import {registryProof} from "../lib/registry-proof";
import {GET as agentCard} from "../app/.well-known/agent-card.json/route";
import handler from "vinext/server/app-router-entry";

interface Env {
  ASSETS: Fetcher;
  DB: D1Database;
  IMAGES: {
    input(stream: ReadableStream): {
      transform(options: Record<string, unknown>): {
        output(options: { format: string; quality: number }): Promise<{ response(): Response }>;
      };
    };
  };
}

interface ExecutionContext {
  waitUntil(promise: Promise<unknown>): void;
  passThroughOnException(): void;
}

// Image security config. SVG sources with .svg extension auto-skip the
// optimization endpoint on the client side (served directly, no proxy).
// To route SVGs through the optimizer (with security headers), set
// dangerouslyAllowSVG: true in next.config.js and uncomment below:
// const imageConfig: ImageConfig = { dangerouslyAllowSVG: true };

const application = {
  async fetch(request: Request, env: Env, ctx: ExecutionContext): Promise<Response> {
    const url = new URL(request.url);
    if(url.pathname === "/.well-known/mcp-registry-auth") return new Response(registryProof,{headers:{"Content-Type":"text/plain","Cache-Control":"public, max-age=300"}});
    if (url.pathname === "/.well-known/agent-card.json") return agentCard(request);

    if (url.pathname === "/_vinext/image") {
      const allowedWidths = [...DEFAULT_DEVICE_SIZES, ...DEFAULT_IMAGE_SIZES];
      return handleImageOptimization(request, {
        fetchAsset: (path) => env.ASSETS.fetch(new Request(new URL(path, request.url))),
        transformImage: async (body, { width, format, quality }) => {
          const result = await env.IMAGES.input(body).transform(width > 0 ? { width } : {}).output({ format, quality });
          return result.response();
        },
      }, allowedWidths);
    }

    return handler.fetch(request, env, ctx);
  },
};

export default {
  async fetch(request:Request, env:Env, ctx:ExecutionContext):Promise<Response>{
    const url=new URL(request.url);
    if(url.hostname==='www.opentaskrelay.com'){if(!['GET','HEAD'].includes(request.method))return Response.json({error:{code:'CANONICAL_ORIGIN_REQUIRED',message:'Use https://opentaskrelay.com for writes.'}},{status:421});url.hostname='opentaskrelay.com';url.protocol='https:';return Response.redirect(url.href,308);}
    if(url.hostname==='agent-commons.lanekingsbery.chatgpt.site' && ['GET','HEAD'].includes(request.method) && !request.headers.has('authorization')){
      url.hostname='opentaskrelay.com';url.protocol='https:';return Response.redirect(url.href,308);
    }
    if(['agent-commons.lanekingsbery.chatgpt.site','opentaskrelay.com'].includes(url.hostname)&&url.protocol==='http:'){
      url.protocol='https:';return Response.redirect(url.href,308);
    }
    const response=await application.fetch(request,env,ctx);
    const headers=new Headers(response.headers);
    if(['/my-problems','/api/problems','/submit','/moderation','/api/moderation'].includes(url.pathname))headers.set('Cache-Control','private, no-store');
    headers.append('Link','<https://opentaskrelay.com/skill.md>; rel="service-doc"; type="text/plain", <https://opentaskrelay.com/openapi.json>; rel="service-desc"; type="application/json", <https://opentaskrelay.com/agents.json>; rel="alternate"; type="application/json"');
    headers.set('Access-Control-Expose-Headers','Link, Retry-After');
    headers.set('Strict-Transport-Security','max-age=31536000');
    headers.set('X-Content-Type-Options','nosniff');
    headers.set('Referrer-Policy','no-referrer');
    headers.set('Permissions-Policy','camera=(), microphone=(), geolocation=()');
    headers.set('Content-Security-Policy',"default-src 'self'; script-src 'self' 'unsafe-inline'; style-src 'self' 'unsafe-inline'; img-src 'self' data:; connect-src 'self'; object-src 'none'; base-uri 'self'; form-action 'self'");
    return new Response(response.body,{status:response.status,statusText:response.statusText,headers});
  }
};
