import os
import sqlite3
import sys
import unittest
from pathlib import Path


ROOT = Path(__file__).resolve().parents[1]
sys.path.insert(0, str(ROOT))

from pms.errors import PMSConfigurationRequired, PMSDuplicateCharge, PMSInvalidRoom
from pms.opera_cloud import OracleOperaCloudConnector
from pms.redaction import redact
from pms.service import PMSService, ensure_pms_tables


class PMSIntegrationTests(unittest.TestCase):
    def setUp(self):
        self.conn = sqlite3.connect(":memory:")
        self.conn.row_factory = sqlite3.Row
        ensure_pms_tables(self.conn)
        self.service = PMSService(self.conn, "default", ["101", "500"])

    def tearDown(self):
        self.conn.close()

    def test_mock_verifies_checked_in_room_without_pii(self):
        result = self.service.verify_room({
            "roomId": "101",
            "secureRoomId": "default-room-101-mock",
        })
        self.assertTrue(result["verified"])
        self.assertEqual(result["roomId"], "101")
        self.assertNotIn("passport", result)
        self.assertNotIn("payment", result)

    def test_mock_rejects_invalid_room(self):
        with self.assertRaises(PMSInvalidRoom):
            self.service.verify_room({"roomId": "999"})

    def test_charge_posting_is_idempotent(self):
        payload = {
            "orderId": "order-1",
            "roomId": "101",
            "amount": 50,
            "currency": "AED",
            "idempotencyKey": "hotel-default-order-1",
        }
        first = self.service.post_charge(payload)
        second = self.service.post_charge(payload)
        self.assertFalse(first["duplicate"])
        self.assertTrue(second["duplicate"])
        rows = self.conn.execute("select count(*) from pms_charge_transactions").fetchone()[0]
        self.assertEqual(rows, 1)

    def test_webhook_event_is_stored(self):
        result = self.service.store_webhook({"eventId": "evt-1", "eventType": "guest_checked_out"})
        self.assertTrue(result["accepted"])
        rows = self.conn.execute("select count(*) from pms_webhook_events").fetchone()[0]
        self.assertEqual(rows, 1)

    def test_redaction_masks_sensitive_data(self):
        clean = redact({
            "client_secret": "secret",
            "guest": {"passport_number": "P123"},
            "amount": 10,
        })
        self.assertEqual(clean["client_secret"], "[redacted]")
        self.assertEqual(clean["guest"]["passport_number"], "[redacted]")
        self.assertEqual(clean["amount"], 10)

    def test_oracle_connector_does_not_invent_endpoints(self):
        for key in [
            "OPERA_BASE_URL",
            "OPERA_CLIENT_ID",
            "OPERA_CLIENT_SECRET",
            "OPERA_APP_KEY",
            "OPERA_ENTERPRISE_ID",
            "OPERA_PROPERTY_ID",
        ]:
            os.environ.pop(key, None)
        connector = OracleOperaCloudConnector({"property_id": "P1"})
        with self.assertRaises(PMSConfigurationRequired):
            connector.getReservation("101")


if __name__ == "__main__":
    unittest.main()
