import 'package:path/path.dart';
import 'package:sqflite/sqflite.dart';
import 'package:unit2/model/passo/additional_items.dart';
import 'package:unit2/model/passo/bldg_loc.dart';
import 'package:unit2/model/passo/general_description.dart';
import 'package:unit2/model/passo/land_ref.dart';
import 'package:unit2/model/passo/property_info.dart';

import '../../../../model/passo/todo.dart';

class PropertyOwnerInfoServices {
  static final PropertyOwnerInfoServices instance =
      PropertyOwnerInfoServices._init();
  static Database? _database;
  PropertyOwnerInfoServices._init();

  Future<Database> get database async {
    if (_database != null) return _database!;

    _database = await _initDB('passo.db');
    return _database!;
  }

  Future<Database> _initDB(String filePath) async {
    final dbPath = await getDatabasesPath();
    final path = join(dbPath, filePath);

    return await openDatabase(path, version: 1, onCreate: _createDB);
  }

  Future _createDB(Database db, int version) async {
    // const idType = 'INTEGER PRIMARY KEY AUTOINCREMENT';
    // const textType = 'TEXT NOT NULL';
    // const boolType = 'BOOLEAN NOT NULL';
    // const integerType = 'INTEGER NOT NULL';

    await db.execute('''
      CREATE TABLE items (
        id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL,
        transCode TEXT NOT NULL,
        tdn TEXT NOT NULL,
        pin TEXT NOT NULL,
        owner TEXT NOT NULL,
        address TEXT NOT NULL,
        telno TEXT NOT NULL,
        tin TEXT NOT NULL,
        adminUser TEXT NOT NULL,
        adminAddress TEXT NOT NULL,
        adminTelno TEXT NOT NULL,
        adminTin TEXT NOT NULL,
        faasType TEXT NOT NULL,
        assessedById TEXT NOT NULL,
        assessedByName TEXT NOT NULL
      )
      ''');

    await db.execute('''
      CREATE TABLE landref (
        id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL,
        bldgapprDetailsId INTEGER NOT NULL,
        assessedById TEXT NOT NULL,
        assessedByName TEXT NOT NULL,
        owner TEXT NOT NULL,
        cloaNo TEXT NOT NULL,
        lotNo TEXT NOT NULL,
        tdn TEXT NOT NULL,
        area TEXT NOT NULL,
        surveyNo TEXT NOT NULL,
        blkNo TEXT NOT NULL
      )
      ''');

    await db.execute('''
      CREATE TABLE location (
         id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL,
         bldgapprDetailsId INTEGER NOT NULL,
         assessedById TEXT NOT NULL,
         assessedByName TEXT NOT NULL,
         street TEXT NOT NULL,
         barangay TEXT NOT NULL,
         municipality TEXT NOT NULL,
         province TEXT NOT NULL
      )
    ''');

    await db.execute('''
      CREATE TABLE additionalitems (
         id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL,
         bldgapprDetailsId INTEGER NOT NULL,
         classId TEXT NOT NULL,
         className TEXT NOT NULL,
         structType TEXT NOT NULL,
         unitValue TEXT NOT NULL,
         baseUnitValue TEXT NOT NULL,
         area TEXT NOT NULL,
         marketValue TEXT NOT NULL,
         depreciationRate TEXT NOT NULL,
         adjustedMarketVal TEXT NOT NULL,
         amtDepreciation TEXT NOT NULL,
         painted TEXT NOT NULL,
         secondhand TEXT NOT NULL,
         paintedUnitval TEXT NOT NULL,
         secondhandUnitval TEXT NOT NULL,
         actualUse TEXT NOT NULL
      )
    ''');
  }

  Future<PropertyInfo> create(PropertyInfo propertyInfo) async {
    final db = await instance.database;

    final data = {
      "id": propertyInfo.id,
      "transCode": propertyInfo.transCode,
      "tdn": propertyInfo.tdn,
      "pin": propertyInfo.pin,
      "fname": propertyInfo.fname,
      "mname": propertyInfo.mname,
      "lname": propertyInfo.lname,
      "bday": propertyInfo.bday,
      "address": propertyInfo.address,
      "telno": propertyInfo.telno,
      "tin": propertyInfo.tin,
      "adminUser": propertyInfo.adminUser,
      "adminAddress": propertyInfo.adminAddress,
      "adminTelno": propertyInfo.adminTelno,
      "adminTin": propertyInfo.adminTin,
      "faasType": propertyInfo.faasType,
      "assessedById": propertyInfo.assessedById,
      "assessedByName": propertyInfo.assessedByName,
    };
    final id = await db.insert('items', data);
    return propertyInfo.copy(id: id);
  }

  Future<LandRef> createLandRef(LandRef landref) async {
    final db = await instance.database;

    final data = {
      "id": landref.id,
      "bldgapprDetailsId": landref.bldgapprDetailsId,
      "assessedById": landref.assessedById,
      "assessedByName": landref.assessedByName,
      "cloaNo": landref.cloaNo,
      "lotNo": landref.lotNo,
      "tdn": landref.tdn,
      "area": landref.area,
      "surveyNo": landref.surveyNo,
      "blkNo": landref.blkNo
    };
    final id = await db.insert('landref', data);
    return landref.copy(id: id);
  }

  Future<BldgLoc> createLocation(BldgLoc loc) async {
    final db = await instance.database;

    final data = {
      "id": loc.id,
      "bldgapprDetailsId": loc.bldgapprDetailsId,
      "assessedById": loc.assessedById,
      "assessedByName": loc.assessedByName,
      "street": loc.street,
      "barangay": loc.barangay,
      "municipality": loc.municipality,
      "province": loc.province
    };
    final id = await db.insert('location', data);
    return loc.copy(id: id);
  }

  Future<GeneralDesc> createGenDesc(GeneralDesc gendesc) async {
    final db = await instance.database;

    final data = {
      "id": gendesc.id,
      "bldgapprDetailsId": gendesc.bldgapprDetailsId,
      "assessedById": gendesc.assessedById,
      "assessedByName": gendesc.assessedByName,
      "dateCreated": gendesc.dateCreated,
      "dateModified": gendesc.dateModified,
      "bldgKind": gendesc.bldgKind,
      "strucType": gendesc.strucType,
      "bldgPermit": gendesc.bldgPermit,
      "dateIssued": gendesc.dateIssued,
      "cct": gendesc.cct,
      "certCompletionIssued": gendesc.certCompletionIssued,
      "certOccupancyIssued": gendesc.certOccupancyIssued,
      "dateCompleted": gendesc.dateCompleted,
      "dateOccupied": gendesc.dateOccupied,
      "bldgAge": gendesc.bldgAge,
      "noStoreys": gendesc.noStoreys,
      "area1Stfloor": gendesc.area1Stfloor,
      "area2Ndfloor": gendesc.area2Ndfloor,
      "area3Rdfloor": gendesc.area3Rdfloor,
      "area4Thfloor": gendesc.area4Thfloor,
      "totalFloorArea": gendesc.totalFloorArea,
      "floorSketch": gendesc.floorSketch,
      "actualUse": gendesc.actualUse
    };
    final id = await db.insert('location', data);
    return gendesc.copy(id: id);
  }

  Future<AdditionalItems> createAdditionalItems(
      AdditionalItems addItems) async {
    final db = await instance.database;

    final data = {
      "id": addItems.id,
      "bldgapprDetailsId": addItems.bldgapprDetailsId,
      "classId": addItems.classId,
      "className": addItems.className,
      "structType": addItems.structType,
      "unitValue": addItems.unitValue,
      "baseUnitValue": addItems.baseUnitValue,
      "area": addItems.area,
      "marketValue": addItems.marketValue,
      "depreciationRate": addItems.depreciationRate,
      "adjustedMarketVal": addItems.adjustedMarketVal,
      "amtDepreciation": addItems.amtDepreciation,
      "painted": addItems.painted,
      "secondhand": addItems.secondhand,
      "paintedUnitval": addItems.paintedUnitval,
      "secondhandUnitval": addItems.secondhandUnitval,
      "actualUse": addItems.actualUse
    };
    final id = await db.insert('additionalitems', data);
    return addItems.copy(id: id);
  }

  Future<Todo> readTodo({required int id}) async {
    final db = await instance.database;

    final maps = await db.query(
      todoTable,
      columns: TodoFields.values,
      where: '${TodoFields.id} = ?',
      whereArgs: [id],
    );

    if (maps.isNotEmpty) {
      return Todo.fromJson(maps.first);
    } else {
      throw Exception('ID $id not found');
    }
  }

  Future<List<PropertyInfo>> readAllTodos() async {
    final db = await instance.database;
    const orderBy = 'id';
    final result = await db.query('items', orderBy: orderBy);

    return result.map((json) => PropertyInfo.fromJson(json)).toList();
  }

  Future<List<AdditionalItems>> readAdditionalItems() async {
    final db = await instance.database;
    const orderBy = 'id';
    final result = await db.query('additional_items', orderBy: orderBy);

    return result.map((json) => AdditionalItems.fromJson(json)).toList();
  }

  Future<int> update({required Todo todo}) async {
    final db = await instance.database;

    return db.update(
      todoTable,
      todo.toJson(),
      where: '${TodoFields.id} = ?',
      whereArgs: [todo.id],
    );
  }

  Future<int> delete({required int id}) async {
    final db = await instance.database;

    return await db.delete(
      'items',
      where: 'id = ?',
      whereArgs: [id],
    );
  }

  Future close() async {
    final db = await instance.database;

    db.close();
  }
}
