import 'dart:io';
import 'package:sqflite/sqflite.dart';
import 'package:path_provider/path_provider.dart';
import '../models/invoice_models.dart';
import '../models/customer_model.dart';
import '../models/customer_contact.dart';
import 'database_helper.dart';
import 'activity_log_repository.dart';

class InvoiceRepository {
  final DatabaseHelper _dbHelper = DatabaseHelper();
  final ActivityLogRepository _logRepo = ActivityLogRepository();

  Future<void> saveInvoice(Invoice invoice) async {
    final db = await _dbHelper.database;

    // 正式発行（下書きでない）場合はロックを掛ける
    final Invoice toSave = invoice.isDraft ? invoice : invoice.copyWith(isLocked: true);

    await db.transaction((txn) async {
      // 最新の連絡先をスナップショットする（なければ空）
      CustomerContact? activeContact;
      final contactRows = await txn.query('customer_contacts', where: 'customer_id = ? AND is_active = 1', whereArgs: [invoice.customer.id]);
      if (contactRows.isNotEmpty) {
        activeContact = CustomerContact.fromMap(contactRows.first);
      }
      final Invoice savingWithContact = toSave.copyWith(
        contactVersionId: activeContact?.version,
        contactEmailSnapshot: activeContact?.email,
        contactTelSnapshot: activeContact?.tel,
        contactAddressSnapshot: activeContact?.address,
      );

      // 在庫の調整（更新の場合、以前の数量を戻してから新しい数量を引く）
      final List<Map<String, dynamic>> oldItems = await txn.query(
        'invoice_items',
        where: 'invoice_id = ?',
        whereArgs: [invoice.id],
      );

      // 旧在庫を戻す
      for (var item in oldItems) {
        if (item['product_id'] != null) {
          await txn.execute(
            'UPDATE products SET stock_quantity = stock_quantity + ? WHERE id = ?',
            [item['quantity'], item['product_id']],
          );
        }
      }

      // 伝票ヘッダーの保存
      await txn.insert(
        'invoices',
        savingWithContact.toMap(),
        conflictAlgorithm: ConflictAlgorithm.replace,
      );

      // 既存の明細を一旦削除
      await txn.delete(
        'invoice_items',
        where: 'invoice_id = ?',
        whereArgs: [invoice.id],
      );

      // 新しい明細の保存と在庫の減算
      for (var item in invoice.items) {
        await txn.insert('invoice_items', item.toMap(invoice.id));
        if (item.productId != null) {
          await txn.execute(
            'UPDATE products SET stock_quantity = stock_quantity - ? WHERE id = ?',
            [item.quantity, item.productId],
          );
          if (!invoice.isDraft) {
            await txn.execute('UPDATE products SET is_locked = 1 WHERE id = ?', [item.productId]);
          }
        }
      }

      // 顧客をロック
      if (!invoice.isDraft) {
        await txn.execute('UPDATE customers SET is_locked = 1 WHERE id = ?', [invoice.customer.id]);
      }
    });

    await _logRepo.logAction(
      action: "SAVE_INVOICE",
      targetType: "INVOICE",
      targetId: invoice.id,
      details: "種別: ${invoice.documentTypeName}, 取引先: ${invoice.customerNameForDisplay}, 合計: ￥${invoice.totalAmount}",
    );
  }

  Future<void> updateInvoice(Invoice invoice) async {
    await saveInvoice(invoice);
  }

  Future<List<Invoice>> getAllInvoices(List<Customer> customers) async {
    final db = await _dbHelper.database;
    List<Map<String, dynamic>> invoiceMaps = await db.query('invoices', orderBy: 'date DESC');

    // サンプル自動投入（伝票が0件なら）
    if (invoiceMaps.isEmpty && customers.isNotEmpty) {
      await _generateSampleInvoices(customers.take(3).toList());
      invoiceMaps = await db.query('invoices', orderBy: 'date DESC');
    }

    List<Invoice> invoices = [];
    for (var iMap in invoiceMaps) {
      final customer = customers.firstWhere(
        (c) => c.id == iMap['customer_id'],
        orElse: () => Customer(id: iMap['customer_id'], displayName: "不明", formalName: "不明"),
      );

      final List<Map<String, dynamic>> itemMaps = await db.query(
        'invoice_items',
        where: 'invoice_id = ?',
        whereArgs: [iMap['id']],
      );

      final items = List.generate(itemMaps.length, (i) => InvoiceItem.fromMap(itemMaps[i]));

      // document_typeのパース
      DocumentType docType = DocumentType.invoice;
      if (iMap['document_type'] != null) {
        try {
          docType = DocumentType.values.firstWhere((e) => e.name == iMap['document_type']);
        } catch (_) {}
      }

      invoices.add(Invoice(
        id: iMap['id'],
        customer: customer,
        date: DateTime.parse(iMap['date']),
        items: items,
        notes: iMap['notes'],
        filePath: iMap['file_path'],
        taxRate: iMap['tax_rate'] ?? 0.10,
        documentType: docType,
        customerFormalNameSnapshot: iMap['customer_formal_name'],
        odooId: iMap['odoo_id'],
        isSynced: iMap['is_synced'] == 1,
        updatedAt: DateTime.parse(iMap['updated_at']),
        latitude: iMap['latitude'],
        longitude: iMap['longitude'],
        terminalId: iMap['terminal_id'] ?? "T1",
        isDraft: (iMap['is_draft'] ?? 0) == 1,
        subject: iMap['subject'],
        isLocked: (iMap['is_locked'] ?? 0) == 1,
        contactVersionId: iMap['contact_version_id'],
        contactEmailSnapshot: iMap['contact_email_snapshot'],
        contactTelSnapshot: iMap['contact_tel_snapshot'],
        contactAddressSnapshot: iMap['contact_address_snapshot'],
      ));
    }
    return invoices;
  }

  Future<void> _generateSampleInvoices(List<Customer> customers) async {
    if (customers.isEmpty) return;
    final now = DateTime.now();
    final items = [
      InvoiceItem(description: "商品A", quantity: 2, unitPrice: 1200),
      InvoiceItem(description: "商品B", quantity: 1, unitPrice: 3000),
    ];
    final List<Invoice> samples = List.generate(
      3,
      (i) => Invoice(
        customer: customers[i % customers.length],
        date: now.subtract(Duration(days: i * 3)),
        items: items,
        isDraft: i == 0, // 1件だけ下書き
        subject: "サンプル案件${i + 1}",
      ),
    );

    for (final inv in samples) {
      await saveInvoice(inv);
    }
  }

  Future<void> deleteInvoice(String id) async {
    final db = await _dbHelper.database;
    await db.transaction((txn) async {
      // 在庫の復元
      final List<Map<String, dynamic>> items = await txn.query(
        'invoice_items',
        where: 'invoice_id = ?',
        whereArgs: [id],
      );

      for (var item in items) {
        if (item['product_id'] != null) {
          await txn.execute(
            'UPDATE products SET stock_quantity = stock_quantity + ? WHERE id = ?',
            [item['quantity'], item['product_id']],
          );
        }
      }

      // PDFパスの取得（削除用）
      final List<Map<String, dynamic>> maps = await txn.query(
        'invoices',
        columns: ['file_path'],
        where: 'id = ?',
        whereArgs: [id],
      );
      
      if (maps.isNotEmpty && maps.first['file_path'] != null) {
        final file = File(maps.first['file_path']);
        if (await file.exists()) {
          await file.delete();
        }
      }

      await txn.delete(
        'invoice_items',
        where: 'invoice_id = ?',
        whereArgs: [id],
      );
      await txn.delete(
        'invoices',
        where: 'id = ?',
        whereArgs: [id],
      );
    });
  }

  Future<int> cleanupOrphanedPdfs() async {
    try {
      final directory = await getExternalStorageDirectory();
      if (directory == null) return 0;

      final files = directory.listSync().whereType<File>().toList();
      final db = await _dbHelper.database;
      final List<Map<String, dynamic>> results = await db.query('invoices', columns: ['file_path']);
      final activePaths = results.map((r) => r['file_path'] as String?).where((p) => p != null).toSet();

      int count = 0;
      for (var file in files) {
        if (file.path.endsWith('.pdf') && !activePaths.contains(file.path)) {
          await file.delete();
          count++;
        }
      }
      return count;
    } catch (e) {
      return 0;
    }
  }

  Future<Map<String, int>> getMonthlySales(int year) async {
    final db = await _dbHelper.database;
    final String yearStr = year.toString();
    final List<Map<String, dynamic>> results = await db.rawQuery('''
      SELECT strftime('%m', date) as month, SUM(total_amount) as total
      FROM invoices
      WHERE strftime('%Y', date) = ? AND document_type = 'invoice'
      GROUP BY month
      ORDER BY month ASC
    ''', [yearStr]);

    Map<String, int> monthlyTotal = {};
    for (var r in results) {
      monthlyTotal[r['month']] = (r['total'] as num).toInt();
    }
    return monthlyTotal;
  }

  Future<int> getYearlyTotal(int year) async {
    final db = await _dbHelper.database;
    final List<Map<String, dynamic>> results = await db.rawQuery('''
      SELECT SUM(total_amount) as total
      FROM invoices
      WHERE strftime('%Y', date) = ? AND document_type = 'invoice'
    ''', [year.toString()]);

    if (results.isEmpty || results.first['total'] == null) return 0;
    return (results.first['total'] as num).toInt();
  }
}
