import { createHash } from 'node:crypto';
import { ApiSourceAdapter } from './api-base.mjs';
import { log } from '../logger.mjs';
import { fileExistsAtAnyLayout } from '../paths.mjs';

const DEFAULT_ENDPOINT = 'https://eu.api.ovh.com/1.0';

function ovhSign(secret, consumerKey, method, url, body, timestamp) {
  const payload = [secret, consumerKey, method, url, body || '', timestamp].join('+');
  return '$1$' + createHash('sha1').update(payload).digest('hex');
}

export class OvhAdapter extends ApiSourceAdapter {
  static key = 'ovh';
  static label = 'OVH';
  static group = 'Hosting';

  endpoint() {
    return this.account.endpoint || DEFAULT_ENDPOINT;
  }

  async ovhFetch(method, path, body = '') {
    const url = `${this.endpoint()}${path}`;
    const ts = Math.floor(Date.now() / 1000).toString();
    const { appKey, appSecret, consumerKey } = this.account.credentials || {};
    if (!appKey || !appSecret || !consumerKey) {
      throw new Error('[ovh] Credentials fehlen: appKey/appSecret/consumerKey');
    }
    const sig = ovhSign(appSecret, consumerKey, method, url, body, ts);

    const headers = {
      'X-Ovh-Application': appKey,
      'X-Ovh-Consumer': consumerKey,
      'X-Ovh-Timestamp': ts,
      'X-Ovh-Signature': sig,
    };
    if (body) headers['Content-Type'] = 'application/json';

    log.debug(`[ovh] ${method} ${path}`);
    const resp = await fetch(url, { method, headers, body: body || undefined });
    if (!resp.ok) {
      const text = await resp.text().catch(() => '');
      throw new Error(`OVH ${method} ${path}: HTTP ${resp.status} — ${text.slice(0, 200)}`);
    }
    return resp;
  }

  async ovhJson(method, path, body) {
    const resp = await this.ovhFetch(method, path, body);
    return resp.json();
  }

  async login() {
    // Sanity-Check: einmal /me abrufen — bestätigt Credentials
    try {
      const me = await this.ovhJson('GET', '/me');
      log.info(`[ovh] Auth OK — ${me.nichandle || me.firstname || 'Account'} (${me.email || me.country})`);
    } catch (e) {
      throw new Error(`[ovh] Auth fehlgeschlagen: ${e.message}`);
    }
  }

  async *iterateItems(kind) {
    // kind: 'bill' (Rechnung) oder 'refund' (Gutschrift)
    const isBill = kind === 'bill';
    const suffix = isBill ? 'Rechnung' : 'Gutschrift';
    let ids;
    try {
      ids = await this.ovhJson('GET', `/me/${kind}`);
    } catch (e) {
      if (/HTTP 403|NOT_GRANTED/.test(e.message)) {
        // Diagnose: aktuelle Rules des Consumer Keys abrufen
        let diag = '';
        try {
          const cred = await this.ovhJson('GET', '/auth/currentCredential');
          const rules = (cred.rules || []).map((r) => `${r.method} ${r.path}`).join(', ');
          diag = `\n[ovh]   Status=${cred.status}, registrierte Rules: ${rules || '<keine>'}`;
        } catch { /* ignore */ }
        log.warn(`[ovh] /me/${kind} nicht freigeschaltet im Consumer Key — überspringe ${suffix}en${diag}`);
        return;
      }
      throw e;
    }
    log.info(`[ovh] ${ids.length} ${isBill ? 'Rechnungen' : 'Gutschriften'}`);

    for (const id of ids) {
      let meta;
      try {
        meta = await this.ovhJson('GET', `/me/${kind}/${id}`);
      } catch (e) {
        log.warn(`[ovh] ${kind} ${id}: Metadaten nicht ladbar (${e.message})`);
        continue;
      }
      const dateIso = (meta.date || '').slice(0, 10); // "2024-08-12"
      if (!dateIso) {
        log.warn(`[ovh] ${kind} ${id}: kein Datum`);
        continue;
      }
      const year = Number(dateIso.slice(0, 4));
      // Pattern "JJJJ-MM-TT <id>.pdf" fuer Bills, Gutschriften zusaetzlich " Gutschrift" — chronologisch sortierbar.
      const filename = isBill
        ? `${dateIso} ${id}.pdf`
        : `${dateIso} ${id} Gutschrift.pdf`;

      // Pre-skip
      if (this.cfg) {
        const existing = fileExistsAtAnyLayout(this.cfg, this.account.folder, year, undefined, filename);
        if (existing) {
          log.info(`[${this.account.id}] skip (bereits vorhanden): ${existing}`);
          continue;
        }
      }

      // PDF-URL: bevorzugt aus Metadata, sonst über /download-Endpoint
      let pdfUrl = meta.pdfUrl;
      if (!pdfUrl) {
        try {
          const dl = await this.ovhJson('GET', `/me/${kind}/${id}/download`);
          pdfUrl = dl.url || dl;
        } catch (e) {
          log.warn(`[ovh] ${kind} ${id}: Download-URL nicht abrufbar (${e.message})`);
          continue;
        }
      }

      try {
        const pdfResp = await fetch(pdfUrl);
        if (!pdfResp.ok) {
          log.warn(`[ovh] ${kind} ${id}: PDF HTTP ${pdfResp.status}`);
          continue;
        }
        const buffer = Buffer.from(await pdfResp.arrayBuffer());
        yield { filename, year, buffer };
      } catch (e) {
        log.warn(`[ovh] ${kind} ${id}: PDF-Download fehlgeschlagen — ${e.message}`);
      }
    }
  }

  async *iterateStatements() {
    yield* this.iterateItems('bill');
    yield* this.iterateItems('refund');
  }
}
