/**
 * AWS S3 adapter — uploads the standalone bundle to an S3 bucket configured for static
 * website hosting. Auth via access key/secret (JSON credentials secret). Connection
 * carries `region`, `bucket`, and optional `baseUrl` (CloudFront/custom domain).
 * Requires the optional `@aws-sdk/client-s3` dependency; missing → clean error.
 */

import fs from 'fs';
import path from 'path';
import { HostingAdapter, DeployInput, DeployResult, parseCreds, optionalRequire } from './types';

const MIME: Record<string, string> = {
  '.html': 'text/html', '.css': 'text/css', '.js': 'application/javascript',
  '.png': 'image/png', '.jpg': 'image/jpeg', '.jpeg': 'image/jpeg', '.webp': 'image/webp',
  '.gif': 'image/gif', '.svg': 'image/svg+xml', '.xml': 'application/xml', '.txt': 'text/plain',
  '.json': 'application/json', '.ico': 'image/x-icon', '.woff2': 'font/woff2', '.woff': 'font/woff',
};

function contentType(rel: string): string {
  return MIME[path.extname(rel).toLowerCase()] || 'application/octet-stream';
}

export const s3Adapter: HostingAdapter = {
  provider: 's3',

  async validate(connection, secret) {
    const sdk = optionalRequire('@aws-sdk/client-s3');
    if (!sdk) return { ok: false, error: 'Server missing "@aws-sdk/client-s3" dependency. Run: npm i @aws-sdk/client-s3' };
    if (!connection.bucket || !connection.region) return { ok: false, error: 'Bucket and region are required' };
    const creds = parseCreds(secret);
    const client = new sdk.S3Client({ region: connection.region, credentials: { accessKeyId: creds.accessKeyId, secretAccessKey: creds.secretAccessKey } });
    try {
      await client.send(new sdk.HeadBucketCommand({ Bucket: connection.bucket }));
      return { ok: true };
    } catch (err: any) {
      return { ok: false, error: err?.message || 'S3 access failed' };
    }
  },

  async deploy({ bundle, connection, secret }: DeployInput): Promise<DeployResult> {
    const sdk = optionalRequire('@aws-sdk/client-s3');
    if (!sdk) throw new Error('Server missing "@aws-sdk/client-s3" dependency. Run: npm i @aws-sdk/client-s3');
    if (!connection.bucket || !connection.region) throw new Error('S3 connection needs a bucket and region.');

    const creds = parseCreds(secret);
    const client = new sdk.S3Client({ region: connection.region, credentials: { accessKeyId: creds.accessKeyId, secretAccessKey: creds.secretAccessKey } });

    for (const f of bundle.files) {
      const Body = await fs.promises.readFile(f.absPath);
      await client.send(new sdk.PutObjectCommand({
        Bucket: connection.bucket,
        Key: f.relPath,
        Body,
        ContentType: contentType(f.relPath),
        CacheControl: f.relPath === 'index.html' ? 'no-cache' : 'public, max-age=31536000',
      }));
    }

    const deployUrl = connection.baseUrl
      || `http://${connection.bucket}.s3-website.${connection.region}.amazonaws.com`;
    return { deployUrl, providerDeployId: bundle.hash };
  },
};
