import express from 'express';
import pool from '../db/pool.js';
import { getAmppConfig } from '../ampp/client.js';
import { rebuildS3Client, buildTestClient, testS3Connection, getS3Bucket } from '../s3/client.js';

const router = express.Router();

// ── S3 / Object Storage ───────────────────────────────────────────────────────

router.get('/s3', async (req, res, next) => {
  try {
    const result = await pool.query(
      `SELECT key, value FROM settings
       WHERE key IN ('s3_endpoint','s3_bucket','s3_access_key','s3_secret_key','s3_region')`
    );
    // Env defaults — surface what's actually wired so the UI doesn't show
    // "not configured" when the container was started with S3_* env vars.
    const envEndpoint  = process.env.S3_ENDPOINT   || '';
    const envBucket    = process.env.S3_BUCKET     || getS3Bucket();
    const envAccessKey = process.env.S3_ACCESS_KEY || '';
    const envSecretKey = process.env.S3_SECRET_KEY || '';
    const envRegion    = process.env.S3_REGION     || 'us-east-1';

    const out = {
      s3_endpoint:   envEndpoint,
      s3_bucket:     envBucket,
      s3_access_key: envAccessKey,
      s3_secret_key_exists: !!envSecretKey,
      s3_region:     envRegion,
      source:        envEndpoint ? 'env' : 'unset',
    };
    for (const { key, value } of result.rows) {
      if (key === 's3_secret_key') {
        if (value) { out.s3_secret_key_exists = true; out.source = 'db'; }
      } else if (value) {
        out[key] = value;
        out.source = 'db';
      }
    }
    res.json(out);
  } catch (err) {
    next(err);
  }
});

router.put('/s3', async (req, res, next) => {
  try {
    const { s3_endpoint, s3_bucket, s3_access_key, s3_secret_key, s3_region } = req.body;

    if (!s3_endpoint) return res.status(400).json({ error: 's3_endpoint is required' });
    if (!s3_bucket)   return res.status(400).json({ error: 's3_bucket is required' });

    const keys = { s3_endpoint, s3_bucket, s3_region: s3_region || 'us-east-1' };
    if (s3_access_key) keys.s3_access_key = s3_access_key;
    if (s3_secret_key) keys.s3_secret_key = s3_secret_key;

    for (const [key, value] of Object.entries(keys)) {
      await pool.query(
        `INSERT INTO settings (key, value, updated_at) VALUES ($1, $2, NOW())
         ON CONFLICT (key) DO UPDATE SET value = $2, updated_at = NOW()`,
        [key, value.trim()]
      );
    }

    // Fetch the full current config (including any previously saved secret)
    const saved = await pool.query(
      `SELECT key, value FROM settings
       WHERE key IN ('s3_endpoint','s3_bucket','s3_access_key','s3_secret_key','s3_region')
         AND value IS NOT NULL AND value <> ''`
    );
    const cfg = {};
    for (const { key, value } of saved.rows) {
      switch (key) {
        case 's3_endpoint':   cfg.endpoint  = value; break;
        case 's3_bucket':     cfg.bucket    = value; break;
        case 's3_access_key': cfg.accessKey = value; break;
        case 's3_secret_key': cfg.secretKey = value; break;
        case 's3_region':     cfg.region    = value; break;
      }
    }
    rebuildS3Client(cfg);

    res.json({ message: 'S3 settings saved and applied' });
  } catch (err) {
    next(err);
  }
});

// Test with the values the browser just typed (before saving), or with saved
// creds if the fields are left blank. Secret is sent only if user typed it.
router.post('/s3/test', async (req, res, next) => {
  try {
    const { s3_endpoint, s3_bucket, s3_access_key, s3_secret_key, s3_region } = req.body;

    // Merge submitted values with anything already saved in the DB
    const saved = await pool.query(
      `SELECT key, value FROM settings
       WHERE key IN ('s3_endpoint','s3_bucket','s3_access_key','s3_secret_key','s3_region')
         AND value IS NOT NULL AND value <> ''`
    );
    const fromDb = {};
    for (const { key, value } of saved.rows) fromDb[key] = value;

    const cfg = {
      endpoint:  (s3_endpoint  || fromDb.s3_endpoint  || '').trim(),
      bucket:    (s3_bucket    || fromDb.s3_bucket    || getS3Bucket()).trim(),
      accessKey: (s3_access_key || fromDb.s3_access_key || '').trim(),
      secretKey: (s3_secret_key || fromDb.s3_secret_key || '').trim(),
      region:    (s3_region    || fromDb.s3_region    || 'us-east-1').trim(),
    };

    if (!cfg.endpoint) return res.status(400).json({ error: 'S3 endpoint is required' });
    if (!cfg.bucket)   return res.status(400).json({ error: 'S3 bucket is required' });

    const client = buildTestClient(cfg);
    const result = await testS3Connection(client, cfg.bucket);
    res.json(result);
  } catch (err) {
    res.status(400).json({ ok: false, error: err.message });
  }
});

// ── AMPP integration ───────────────────────────────────────────────────────────

router.get('/ampp', async (req, res, next) => {
  try {
    const result = await pool.query(
      "SELECT key, value FROM settings WHERE key IN ('ampp_base_url', 'ampp_token')"
    );
    const out = {};
    for (const row of result.rows) {
      if (row.key === 'ampp_token') {
        out.ampp_token_exists = true;
      } else {
        out[row.key] = row.value;
      }
    }
    res.json(out);
  } catch (err) {
    next(err);
  }
});

router.put('/ampp', async (req, res, next) => {
  try {
    const { ampp_base_url, ampp_token } = req.body;
    if (!ampp_base_url) return res.status(400).json({ error: 'ampp_base_url is required' });
    const baseUrl = ampp_base_url.trim().replace(/\/$/, '');
    await pool.query(
      `INSERT INTO settings (key, value, updated_at) VALUES ('ampp_base_url', $1, NOW())
       ON CONFLICT (key) DO UPDATE SET value = $1, updated_at = NOW()`,
      [baseUrl]
    );
    if (ampp_token) {
      await pool.query(
        `INSERT INTO settings (key, value, updated_at) VALUES ('ampp_token', $1, NOW())
         ON CONFLICT (key) DO UPDATE SET value = $1, updated_at = NOW()`,
        [ampp_token.trim()]
      );
    }
    res.json({ message: 'AMPP settings saved' });
  } catch (err) {
    next(err);
  }
});

router.post('/ampp/test', async (req, res, next) => {
  try {
    const config = await getAmppConfig();
    if (!config) return res.status(400).json({ error: 'AMPP credentials not configured' });
    const testUrl = `${config.ampp_base_url}/api/v1/store/folder/folders?limit=1`;
    const testRes = await fetch(testUrl, {
      headers: { Authorization: `Bearer ${config.ampp_token}`, 'Content-Type': 'application/json' },
    });
    if (!testRes.ok) return res.status(400).json({ error: `AMPP returned HTTP ${testRes.status}` });
    res.json({ message: 'AMPP connection successful' });
  } catch (err) {
    res.status(400).json({ error: `Connection failed: ${err.message}` });
  }
});

// ── Hardware inventory ────────────────────────────────────────────────────────

router.get('/hardware', async (req, res, next) => {
  try {
    const result = await pool.query(
      `SELECT id, hostname, role, ip_address, capabilities,
              EXTRACT(EPOCH FROM (NOW() - last_seen))::int AS stale_seconds
       FROM cluster_nodes
       ORDER BY role, hostname`
    );
    const nodes = result.rows.map(n => ({
      id:           n.id,
      hostname:     n.hostname,
      role:         n.role,
      ip_address:   n.ip_address,
      online:       n.stale_seconds < 120,
      capabilities: n.capabilities || {},
    }));
    res.json({ nodes });
  } catch (err) {
    next(err);
  }
});

// ── GPU / Transcoding ─────────────────────────────────────────────────────────

router.get('/transcoding', async (req, res, next) => {
  try {
    const result = await pool.query(
      `SELECT key, value FROM settings
       WHERE key IN ('gpu_transcode_enabled','gpu_codec','gpu_preset','gpu_bitrate_mbps','gpu_node',
                     'gpu_extension','gpu_framerate','gpu_rc_mode','gpu_audio_codec','gpu_audio_bitrate_kbps')`
    );
    const out = {
      gpu_transcode_enabled:  'false',
      gpu_codec:              'h264_nvenc',
      gpu_preset:             'p4',
      gpu_bitrate_mbps:       '8',
      gpu_node:               '',
      gpu_extension:          'mp4',
      gpu_framerate:          'passthrough',
      gpu_rc_mode:            'cbr',
      gpu_audio_codec:        'aac',
      gpu_audio_bitrate_kbps: '192',
    };
    for (const { key, value } of result.rows) out[key] = value;
    res.json(out);
  } catch (err) {
    next(err);
  }
});

router.put('/transcoding', async (req, res, next) => {
  try {
    const allowed = [
      'gpu_transcode_enabled', 'gpu_codec', 'gpu_preset', 'gpu_bitrate_mbps', 'gpu_node',
      'gpu_extension', 'gpu_framerate', 'gpu_rc_mode', 'gpu_audio_codec', 'gpu_audio_bitrate_kbps',
    ];
    for (const key of allowed) {
      if (req.body[key] !== undefined) {
        await pool.query(
          `INSERT INTO settings (key, value, updated_at) VALUES ($1, $2, NOW())
           ON CONFLICT (key) DO UPDATE SET value = $2, updated_at = NOW()`,
          [key, String(req.body[key])]
        );
      }
    }
    res.json({ message: 'Transcoding settings saved' });
  } catch (err) {
    next(err);
  }
});

// ── Growing files (SMB landing zone) ─────────────────────────────────────────
// Lets capture write its master output to a fast local SMB share instead of
// streaming directly to S3. Premiere can mount the share and edit the file
// while it's still being written; the promotion worker later moves the
// finalized file to S3 and flips the asset to status='ready'.

// Growing-files mode is now a PER-RECORDER setting (recorders.growing_enabled);
// the legacy global `growing_enabled` key is no longer read at recorder start.
// These global keys describe the shared SMB landing-zone infrastructure only:
//   - growing_path                  container mount point (default /growing)
//   - growing_smb_url               smb://... display string for editors (Premiere)
//   - growing_smb_mount             //host/share CIFS source the capture container mounts
//   - growing_smb_username          SMB user for the system-side CIFS mount
//   - growing_smb_password          SMB password (WRITE-ONLY; never returned)
//   - growing_smb_vers              CIFS protocol version (default 3.0)
//   - growing_promote_after_seconds idle threshold before S3 promotion
const GROWING_KEYS = [
  'growing_path', 'growing_smb_url', 'growing_smb_mount',
  'growing_smb_username', 'growing_smb_vers', 'growing_promote_after_seconds',
];
// growing_smb_password is handled separately: stored on PUT but NEVER returned
// on GET (only a *_exists flag), mirroring s3_secret_key.

router.get('/growing', async (req, res, next) => {
  try {
    const result = await pool.query(
      `SELECT key, value FROM settings WHERE key = ANY($1)`,
      [[...GROWING_KEYS, 'growing_smb_password']]
    );
    const out = {
      growing_path: '/growing',
      growing_smb_url: '',
      growing_smb_mount: '',
      growing_smb_username: '',
      growing_smb_vers: '3.0',
      growing_promote_after_seconds: '8',
      growing_smb_password_exists: false,
    };
    for (const { key, value } of result.rows) {
      if (key === 'growing_smb_password') {
        out.growing_smb_password_exists = !!(value && value.length);
      } else {
        out[key] = value;
      }
    }
    res.json(out);
  } catch (err) {
    next(err);
  }
});

router.put('/growing', async (req, res, next) => {
  try {
    for (const key of GROWING_KEYS) {
      if (req.body[key] !== undefined) {
        await pool.query(
          `INSERT INTO settings (key, value, updated_at) VALUES ($1, $2, NOW())
           ON CONFLICT (key) DO UPDATE SET value = $2, updated_at = NOW()`,
          [key, String(req.body[key])]
        );
      }
    }
    // SMB password is write-only. A non-empty value sets/replaces it. To remove
    // it, send growing_smb_password_clear:true. A blank/omitted password field
    // leaves the stored value untouched (so operators don't retype it on every
    // save).
    if (req.body.growing_smb_password_clear === true) {
      await pool.query(`DELETE FROM settings WHERE key = 'growing_smb_password'`);
    } else if (typeof req.body.growing_smb_password === 'string' && req.body.growing_smb_password.length > 0) {
      await pool.query(
        `INSERT INTO settings (key, value, updated_at) VALUES ('growing_smb_password', $1, NOW())
         ON CONFLICT (key) DO UPDATE SET value = $1, updated_at = NOW()`,
        [req.body.growing_smb_password]
      );
    }
    res.json({ message: 'Growing-files settings saved' });
  } catch (err) {
    next(err);
  }
});

// ── Capture service routing ───────────────────────────────────────────────────

router.get('/capture-service', async (req, res, next) => {
  try {
    const result = await pool.query(
      "SELECT value FROM settings WHERE key = 'capture_service_url'"
    );
    res.json({ capture_service_url: result.rows[0]?.value || '' });
  } catch (err) {
    next(err);
  }
});

router.put('/capture-service', async (req, res, next) => {
  try {
    const url = (req.body.capture_service_url || '').trim().replace(/\/$/, '');
    await pool.query(
      `INSERT INTO settings (key, value, updated_at) VALUES ('capture_service_url', $1, NOW())
       ON CONFLICT (key) DO UPDATE SET value = $1, updated_at = NOW()`,
      [url]
    );
    res.json({ message: 'Capture service URL saved' });
  } catch (err) {
    next(err);
  }
});

export default router;
