<?php

namespace Espo\Custom\Services;

use Espo\Core\Exceptions\Forbidden;
use Espo\Core\Exceptions\NotFound;
use Espo\Tools\Stream\Service as StreamService;
use Espo\Entities\Note;

class CVmhMietverhltnis extends \Espo\Services\Record
{
    /**
     * Initiate eviction lawsuit (Räumungsklage) from Mietverhältnis
     * 
     * @param string $mietverhaeltnisId
     * @return array
     * @throws NotFound
     * @throws Forbidden
     */
    public function initiateEviction(string $mietverhaeltnisId): array
    {
        // Delegate to CVmhRumungsklage service
        $raeumungsklagenService = $this->serviceFactory->create('CVmhRumungsklage');
        return $raeumungsklagenService->createFromSource('CVmhMietverhltnis', $mietverhaeltnisId);
    }
    
    /**
     * Initiate rent collection (Mietinkasso) from Mietverhältnis
     * 
     * @param string $mietverhaeltnisId
     * @return array
     * @throws NotFound
     * @throws Forbidden
     */
    public function initiateRentCollection(string $mietverhaeltnisId): array
    {
        // 1. Load Mietverhältnis
        $mietverhaeltnis = $this->entityManager->getEntity('CVmhMietverhltnis', $mietverhaeltnisId);
        if (!$mietverhaeltnis) {
            throw new NotFound('Mietverhältnis not found');
        }
        
        // 2. ACL Checks
        if (!$this->acl->check($mietverhaeltnis, 'read')) {
            throw new Forbidden('No read access to Mietverhältnis');
        }
        
        if (!$this->acl->checkScope('CMietinkasso', 'create')) {
            throw new Forbidden('No create access to Mietinkasso');
        }
        
        // 3. Start Transaction
        $this->entityManager->getTransactionManager()->start();
        
        try {
            // 4. Prepare data for new Mietinkasso
            $data = new \stdClass();
            $data->name = 'Mietinkasso - ' . $mietverhaeltnis->get('name');
            
            // Copy assignedUser and teams
            if ($mietverhaeltnis->get('assignedUserId')) {
                $data->assignedUserId = $mietverhaeltnis->get('assignedUserId');
            }
            
            $teamsIds = $mietverhaeltnis->getLinkMultipleIdList('teams');
            if (!empty($teamsIds)) {
                $data->teamsIds = $teamsIds;
            }
            
            // 5. Create Mietinkasso entity
            $mietinkasso = $this->entityManager->createEntity('CMietinkasso', (array)$data);
            
            if (!$mietinkasso) {
                throw new \RuntimeException('Failed to create Mietinkasso');
            }
            
            $mietinkassoRepo = $this->entityManager->getRepository('CMietinkasso');
            
            // 6. Link Mietverhältnis to Mietinkasso
            $mietinkassoRepo
                ->getRelation($mietinkasso, 'vmhMietverhltnises')
                ->relate($mietverhaeltnis);
            
            // 7. Get Mietobjekt (for document collection only, not linked directly)
            $mietobjekt = $this->entityManager
                ->getRepository('CVmhMietverhltnis')
                ->getRelation($mietverhaeltnis, 'vmhMietobjekt')
                ->findOne();
            
            // Note: Mietobjekt wird NICHT mehr direkt zum Mietinkasso gelinkt
            // Die Verbindung erfolgt indirekt über Mietverhältnis
            
            // 8. Get Vermieter (Kläger) from Mietverhältnis
            $vermieterBeteiligte = $this->entityManager
                ->getRepository('CVmhMietverhltnis')
                ->getRelation($mietverhaeltnis, 'vmhbeteiligtevermieter')
                ->find();
            
            foreach ($vermieterBeteiligte as $vermieter) {
                // Link as Kläger
                $mietinkassoRepo
                    ->getRelation($mietinkasso, 'klaeger')
                    ->relate($vermieter);
            }
            
            // 9. Get Mieter (Beklagte) from Mietverhältnis
            $mieterBeteiligte = $this->entityManager
                ->getRepository('CVmhMietverhltnis')
                ->getRelation($mietverhaeltnis, 'vmhbeteiligtemieter')
                ->find();
            
            foreach ($mieterBeteiligte as $mieter) {
                // Link as Beklagte
                $mietinkassoRepo
                    ->getRelation($mietinkasso, 'beklagte')
                    ->relate($mieter);
            }
            
            // 9b. Get Sonstige Bewohner (auch Beklagte) from Mietverhältnis
            $sonstigeBewohner = $this->entityManager
                ->getRepository('CVmhMietverhltnis')
                ->getRelation($mietverhaeltnis, 'sonstigebesitzervmhmietverhltnis')
                ->find();
            
            foreach ($sonstigeBewohner as $bewohner) {
                // Link as Beklagte
                $mietinkassoRepo
                    ->getRelation($mietinkasso, 'beklagte')
                    ->relate($bewohner);
            }
            
            // 10. Copy all documents from Mietverhältnis, Mietobjekt and Beteiligte
            // 10a. Dokumente vom Mietverhältnis
            $dokumenteMV = $this->entityManager
                ->getRepository('CVmhMietverhltnis')
                ->getRelation($mietverhaeltnis, 'dokumentesvmhMietverhltnisse')
                ->find();
            
            foreach ($dokumenteMV as $dokument) {
                $mietinkassoRepo
                    ->getRelation($mietinkasso, 'dokumentesmietinkasso')
                    ->relate($dokument);
            }
            
            // 10b. Dokumente vom Mietobjekt
            if ($mietobjekt) {
                $dokumenteMO = $this->entityManager
                    ->getRepository('CMietobjekt')
                    ->getRelation($mietobjekt, 'dokumentesMietobjekt')
                    ->find();
                
                foreach ($dokumenteMO as $dokument) {
                    $mietinkassoRepo
                        ->getRelation($mietinkasso, 'dokumentesmietinkasso')
                        ->relate($dokument);
                }
            }
            
            // 10c. Dokumente von allen Beteiligten (Vermieter + Mieter + Sonstige)
            $alleBeteiligte = array_merge(
                iterator_to_array($vermieterBeteiligte),
                iterator_to_array($mieterBeteiligte),
                iterator_to_array($sonstigeBewohner)
            );
            
            foreach ($alleBeteiligte as $beteiligter) {
                $dokumenteBet = $this->entityManager
                    ->getRepository('CBeteiligte')
                    ->getRelation($beteiligter, 'dokumentesBeteiligte')
                    ->find();
                
                foreach ($dokumenteBet as $dokument) {
                    $mietinkassoRepo
                        ->getRelation($mietinkasso, 'dokumentesmietinkasso')
                        ->relate($dokument);
                }
            }
            
            // 11. Copy portal contacts from Mietverhältnis (nur vom Mietverhältnis!)
            $portalContacts = $this->entityManager
                ->getRepository('CVmhMietverhltnis')
                ->getRelation($mietverhaeltnis, 'contactsMietverhltnis')
                ->find();
            
            foreach ($portalContacts as $contact) {
                $mietinkassoRepo
                    ->getRelation($mietinkasso, 'contactsMietinkasso')
                    ->relate($contact);
            }
            
            // 12. Log to stream
            $this->logToStream($mietverhaeltnis, 'CVmhMietverhltnis', $mietinkasso->getId(), 'CMietinkasso', 'Mietinkasso erstellen');
            
            // 13. Commit transaction
            $this->entityManager->getTransactionManager()->commit();
            
            return [
                'id' => $mietinkasso->getId(),
                'name' => $mietinkasso->get('name')
            ];
        } catch (\Exception $e) {
            // Rollback on any error
            $this->entityManager->getTransactionManager()->rollback();
            throw $e;
        }
    }
    
    /**
     * Initiate termination (Kündigung) from Mietverhältnis
     * 
     * @param string $mietverhaeltnisId
     * @return array
     * @throws NotFound
     * @throws Forbidden
     */
    public function initiateTermination(string $mietverhaeltnisId): array
    {
        // 1. Load Mietverhältnis
        $mietverhaeltnis = $this->entityManager->getEntity('CVmhMietverhltnis', $mietverhaeltnisId);
        if (!$mietverhaeltnis) {
            throw new NotFound('Mietverhältnis not found');
        }
        
        // 2. ACL Checks
        if (!$this->acl->check($mietverhaeltnis, 'read')) {
            throw new Forbidden('No read access to Mietverhältnis');
        }
        
        if (!$this->acl->checkScope('CKuendigung', 'create')) {
            throw new Forbidden('No create access to Kündigung');
        }
        
        // 3. Start Transaction
        $this->entityManager->getTransactionManager()->start();
        
        try {
            // 4. Prepare data for new Kündigung
            $data = new \stdClass();
            $data->name = 'Kündigung - ' . $mietverhaeltnis->get('name');
            
            // Copy assignedUser and teams
            if ($mietverhaeltnis->get('assignedUserId')) {
                $data->assignedUserId = $mietverhaeltnis->get('assignedUserId');
            }
            
            $teamsIds = $mietverhaeltnis->getLinkMultipleIdList('teams');
            if (!empty($teamsIds)) {
                $data->teamsIds = $teamsIds;
            }
            
            // 5. Create Kündigung entity
            $kuendigung = $this->entityManager->createEntity('CKuendigung', (array)$data);
            
            if (!$kuendigung) {
                throw new \RuntimeException('Failed to create Kündigung');
            }
            
            $kuendigungRepo = $this->entityManager->getRepository('CKuendigung');
            
            // 6. Link Mietverhältnis to Kündigung
            $kuendigungRepo
                ->getRelation($kuendigung, 'vmhMietverhltnises')
                ->relate($mietverhaeltnis);
            
            // 7. Get Vermieter from Mietverhältnis
            $vermieterBeteiligte = $this->entityManager
                ->getRepository('CVmhMietverhltnis')
                ->getRelation($mietverhaeltnis, 'vmhbeteiligtevermieter')
                ->find();
            
            foreach ($vermieterBeteiligte as $vermieter) {
                // Link as Kuendiger (Vermieter)
                $kuendigungRepo
                    ->getRelation($kuendigung, 'kuendiger')
                    ->relate($vermieter);
            }
            
            // 8. Get Mieter from Mietverhältnis (NUR Mieter, NICHT sonstige Bewohner!)
            $mieterBeteiligte = $this->entityManager
                ->getRepository('CVmhMietverhltnis')
                ->getRelation($mietverhaeltnis, 'vmhbeteiligtemieter')
                ->find();
            
            foreach ($mieterBeteiligte as $mieter) {
                // Link as Gekuendigte (Mieter)
                $kuendigungRepo
                    ->getRelation($kuendigung, 'gekuendigte')
                    ->relate($mieter);
            }
            
            // 9. Copy all documents from Mietverhältnis and Beteiligte
            // 9a. Dokumente vom Mietverhältnis
            $dokumenteMV = $this->entityManager
                ->getRepository('CVmhMietverhltnis')
                ->getRelation($mietverhaeltnis, 'dokumentesvmhMietverhltnisse')
                ->find();
            
            foreach ($dokumenteMV as $dokument) {
                $kuendigungRepo
                    ->getRelation($kuendigung, 'dokumenteskuendigung')
                    ->relate($dokument);
            }
            
            // 9b. Dokumente von allen Beteiligten (Vermieter + Mieter)
            $alleBeteiligte = array_merge(
                iterator_to_array($vermieterBeteiligte),
                iterator_to_array($mieterBeteiligte)
            );
            
            foreach ($alleBeteiligte as $beteiligter) {
                $dokumenteBet = $this->entityManager
                    ->getRepository('CBeteiligte')
                    ->getRelation($beteiligter, 'dokumentesBeteiligte')
                    ->find();
                
                foreach ($dokumenteBet as $dokument) {
                    $kuendigungRepo
                        ->getRelation($kuendigung, 'dokumenteskuendigung')
                        ->relate($dokument);
                }
            }
            
            // 10. Copy portal contacts from Mietverhältnis (nur vom Mietverhältnis!)
            $portalContacts = $this->entityManager
                ->getRepository('CVmhMietverhltnis')
                ->getRelation($mietverhaeltnis, 'contactsMietverhltnis')
                ->find();
            
            foreach ($portalContacts as $contact) {
                $kuendigungRepo
                    ->getRelation($kuendigung, 'contactsKuendigung')
                    ->relate($contact);
            }
            
            // 11. Log to stream
            $this->logToStream($mietverhaeltnis, 'CVmhMietverhltnis', $kuendigung->getId(), 'CKuendigung', 'Kündigung erstellen');
            
            // 12. Commit transaction
            $this->entityManager->getTransactionManager()->commit();
            
            return [
                'id' => $kuendigung->getId(),
                'name' => $kuendigung->get('name')
            ];
        } catch (\Exception $e) {
            // Rollback on any error
            $this->entityManager->getTransactionManager()->rollback();
            throw $e;
        }
    }
    
    /**
     * Log action to source entity stream
     * 
     * @param object $sourceEntity Source entity (Mietverhältnis)
     * @param string $sourceEntityType Entity type
     * @param string $createdEntityId Created entity ID
     * @param string $createdEntityType Created entity type
     * @param string $actionLabel Label for the action
     */
    private function logToStream($sourceEntity, string $sourceEntityType, string $createdEntityId, string $createdEntityType, string $actionLabel): void
    {
        // Create Note entity manually for custom message
        $note = $this->entityManager->getEntity('Note');
        $note->set([
            'type' => Note::TYPE_CREATE_RELATED,
            'parentType' => $sourceEntityType,
            'parentId' => $sourceEntity->getId(),
            'relatedType' => $createdEntityType,
            'relatedId' => $createdEntityId,
            'data' => [
                'actionLabel' => $actionLabel
            ]
        ]);
        
        $this->entityManager->saveEntity($note);
    }
}
