import fp from "fastify-plugin";
import type { FastifyInstance } from "fastify";
import { MockStorage, AwsStorage, type StorageService, createStorageService } from "@app/storage";

declare module "fastify" {
  interface FastifyInstance {
    storage: StorageService;
  }
}

export const storagePlugin = fp(async (app: FastifyInstance) => {
  let storage: StorageService;
  if (app.config.S3_MODE === "aws") {
    const aws = new AwsStorage({
      bucket: app.config.S3_BUCKET,
      region: app.config.S3_REGION,
      endpoint: app.config.S3_ENDPOINT || undefined,
      accessKeyId: app.config.S3_ACCESS_KEY_ID || undefined,
      secretAccessKey: app.config.S3_SECRET_ACCESS_KEY || undefined,
    });
    // Verifiera bucket-åtkomst vid uppstart – produktion ska aldrig starta halvtrasig.
    try {
      await aws.healthCheck();
      app.log.info(`S3: riktig lagring aktiv (bucket: ${app.config.S3_BUCKET})`);
    } catch (err) {
      if (app.config.NODE_ENV === "production") {
        throw new Error(
          `S3-bucketen "${app.config.S3_BUCKET}" är inte nåbar: ${(err as Error).message}`,
        );
      }
      app.log.error(
        `S3-bucketen "${app.config.S3_BUCKET}" svarar inte (${(err as Error).message}) – kontrollera S3_*-värdena.`,
      );
    }
    storage = aws;
    app.decorate("storage", storage);
    return; // riktiga presignade URL:er – inga lokala S3-endpoints behövs
  }

  const mockStorage = new MockStorage(
    app.config.API_BASE_URL,
    app.config.ENTITLEMENT_SIGNING_SECRET,
  );
  storage = mockStorage;
  app.decorate("storage", storage);

  // Mock-S3-endpoints (endast i mock-läge)
  app.addContentTypeParser(
    ["image/jpeg", "image/png", "image/webp", "image/heic", "application/octet-stream"],
    { parseAs: "buffer", bodyLimit: 15 * 1024 * 1024 },
    (_req, body, done) => done(null, body),
  );

  app.put<{ Params: { key: string }; Querystring: { sig?: string } }>(
    "/v1/mock-s3/:key",
    { config: { rateLimit: false } },
    async (req, reply) => {
      const key = decodeURIComponent(req.params.key);
      if (!mockStorage.verifySignature(key, req.query.sig ?? "")) {
        return reply
          .status(403)
          .send({ error: { code: "BAD_SIGNATURE", message: "Ogiltig signatur" } });
      }
      const body = req.body as Buffer | undefined;
      if (!body || body.length === 0) {
        return reply.status(400).send({ error: { code: "EMPTY_BODY", message: "Tom fil" } });
      }
      await mockStorage.putObject(
        key,
        body,
        req.headers["content-type"] ?? "application/octet-stream",
      );
      return reply.status(200).send({ ok: true, key });
    },
  );

  app.get<{ Params: { key: string }; Querystring: { sig?: string } }>(
    "/v1/mock-s3/:key",
    { config: { rateLimit: false } },
    async (req, reply) => {
      const key = decodeURIComponent(req.params.key);
      if (!mockStorage.verifySignature(key, req.query.sig ?? "")) {
        return reply
          .status(403)
          .send({ error: { code: "BAD_SIGNATURE", message: "Ogiltig signatur" } });
      }
      const data = await mockStorage.getObject(key);
      if (!data)
        return reply
          .status(404)
          .send({ error: { code: "NOT_FOUND", message: "Filen finns inte" } });
      return reply.header("content-type", "application/octet-stream").send(data);
    },
  );
});

export { createStorageService };
