/**
 * JSON Sales Return Repository Adapter
 * Persists returns to JSON file
 */

import { mkdir, readFile, writeFile } from 'fs/promises';
import { dirname, join } from 'path';

import type { SalesReturn } from '../domain/sales-return.model';
import type { SalesReturnRepository, CreateSalesReturnRepositoryInput, UpdateSalesReturnRepositoryInput } from '../application/sales-return-repository';

const RETURNS_FILE = join(process.cwd(), 'db', 'sales_returns.json');

interface SalesReturnStorage extends SalesReturn {
  // Ensure all required fields are present
}

export class JsonSalesReturnRepository implements SalesReturnRepository {
  private async loadReturns(): Promise<Map<string, SalesReturnStorage>> {
    try {
      const data = await readFile(RETURNS_FILE, 'utf-8');
      const parsed = JSON.parse(data) as SalesReturnStorage[];
      return new Map(parsed.map((r) => [r.id, r]));
    } catch {
      // File doesn't exist or is invalid, return empty map
      return new Map();
    }
  }

  private async saveReturns(returns: Map<string, SalesReturnStorage>): Promise<void> {
    const array = Array.from(returns.values());
    await mkdir(dirname(RETURNS_FILE), { recursive: true });
    await writeFile(RETURNS_FILE, JSON.stringify(array, null, 2), 'utf-8');
  }

  async list(): Promise<SalesReturn[]> {
    const returns = await this.loadReturns();
    return Array.from(returns.values());
  }

  async getById(id: string): Promise<SalesReturn | null> {
    const returns = await this.loadReturns();
    return returns.get(id) || null;
  }

  async getByInvoiceId(invoiceId: string): Promise<SalesReturn[]> {
    const returns = await this.loadReturns();
    return Array.from(returns.values()).filter(
      (r) => r.invoiceId === invoiceId
    );
  }

  async getByCustomerId(customerId: string): Promise<SalesReturn[]> {
    const returns = await this.loadReturns();
    return Array.from(returns.values()).filter(
      (r) => r.customerId === customerId
    );
  }

  async getByStatus(status: string): Promise<SalesReturn[]> {
    const returns = await this.loadReturns();
    return Array.from(returns.values()).filter(
      (r) => r.status === status
    );
  }

  async create(input: CreateSalesReturnRepositoryInput): Promise<SalesReturn> {
    const returns = await this.loadReturns();
    const salesReturn: SalesReturnStorage = {
      ...input,
    } as SalesReturnStorage;
    returns.set(salesReturn.id, salesReturn);
    await this.saveReturns(returns);
    return salesReturn;
  }

  async update(
    id: string,
    input: UpdateSalesReturnRepositoryInput
  ): Promise<SalesReturn | null> {
    const returns = await this.loadReturns();
    const existing = returns.get(id);
    if (!existing) {
      return null;
    }

    const updated: SalesReturnStorage = {
      ...existing,
      ...input,
      updatedAt: new Date().toISOString(),
    } as SalesReturnStorage;

    returns.set(id, updated);
    await this.saveReturns(returns);
    return updated;
  }

  async delete(id: string): Promise<boolean> {
    const returns = await this.loadReturns();
    const deleted = returns.delete(id);
    if (deleted) {
      await this.saveReturns(returns);
    }
    return deleted;
  }

  async getNextReturnNumber(year: number): Promise<string> {
    const returns = await this.loadReturns();
    const yearReturns = Array.from(returns.values()).filter((r) =>
      r.returnNumber.startsWith(`R/${year}`)
    );

    const maxSequence = Math.max(
      0,
      ...yearReturns.map((r) => {
        const parts = r.returnNumber.split('/');
        return parseInt(parts[2] || '0', 10);
      })
    );

    const nextSequence = (maxSequence + 1).toString().padStart(4, '0');
    return `R/${year}/${nextSequence}`;
  }
}
