
    \hF                     v   U d dl Z d dlmZmZmZmZ d dlmZmZ d dl	m
Z
 d dlmZ d dlmZ d dlmZ d dlmZ d d	lmZ d d
lmZmZmZ d dlmZ d dlmZmZmZmZm Z  d dl!m!Z!m"Z" d dl#Z# e        ddddddddZ$de%de%fdZ&de%de%fdZ' G d de      Z( G d de      Z) G d d e      Z* G d! d"e      Z+ G d# d$e      Z, G d% d&e      Z- G d' d(e      Z. G d) d*e(      Z/ G d+ d,e(      Z0 G d- d.e(      Z1 ed/d01      Z2e2jg                  ed2gd3d2gd2g4        e       Z4 e jj                  d5      Z6 e jj                  d6      Z7da8ee9d7<   da:ee9d8<   e2jw                  d9ed:d;g<      d=        Z<e2jw                  d>ed:d;g<      d?        Z=e2jw                  d@ed:d;g<      dA        Z=e2j}                  dB      dC        Z?e2j}                  dD      dE        Z@dFe%fdGZAdHe%fdIZBdJe%dKeCdLefdMZDdJe%dLedee   fdNZEe4j                  dOe/ej                  dPgQ      dRe/fdS       ZHe4jw                  dOee/   dPgT      dU        ZIe4jw                  dVee)   dWgT      dXe%fdY       ZJe4jw                  dZee*   dWgT       e d[d\]       e d[d^]      fd_e%dXe%d`e%fda       ZKe4j                  dbe0ej                  dcgQ      dde0fde       ZLe4jw                  dbee0   dcgT      df        ZMe4j                  dge1ej                  dhgQ      die1fdj       ZNe4jw                  dgee1   dhgT      dk        ZOe4jw                  dlee1   dhgT      dme%fdn       ZPe4j                  doe+dhgT       e d[dp]      fdqe%dre%fds       ZRe2j                  e4       e2j                  dt e
duv      duw       eUdxk(  r e#j                  dydzd{d3d0|       yy)}    N)ListAnyOptionalDict)HTMLResponseFileResponse)StaticFiles)CORSMiddleware)MongoClient)ObjectId)	InvalidId)load_dotenv)	BaseModelField
ConfigDict)ServerSelectionTimeoutError)FastAPIHTTPExceptionstatus	APIRouterQuery)datetime	timedeltaLunesMartesu
   MiércolesJuevesViernesu   SábadoDomingo)r                     date_strreturnc                     	 t        j                  | d      }t        |j                            S # t        $ r t        dd      w xY w)Nz%Y-%m-%d  u+   Formato de fecha inválido. Use YYYY-MM-DD.status_codedetail)r   strptimeDAY_MAPweekday
ValueErrorr   )r%   dts     +/opt/tws/lhia-sport/api/fast_api_canchas.pyget_day_name_in_spanishr2      sJ    cx4rzz|$$ c4abbcs	   ,/ Astart_time_strc                     	 t        j                  | d      }|t        d      z   }|j                  d      S # t        $ r t        dd      w xY w)Nz%H:%Mr   )hoursr(   u%   Formato de hora inválido. Use HH:MM.r)   )r   r,   r   strftimer/   r   )r3   
start_timeend_times      r1   get_end_timer9   !   sY    ]&&~w?
	 22  )) ]4[\\]s	   58 Ac                   N    e Zd ZU  edd      Zee   ed<    eddddii      Z	y)	MongoBaseModel_idN)aliasdefaultidTexample60d5ec49b14f6b3d4f4d4e3a)populate_by_namejson_schema_extra)
__name__
__module____qualname__r   r?   r   str__annotations__r   model_config     r1   r;   r;   *   s2    E48B8$t-G&HILrK   r;   c                       e Zd ZU  edd      Zeed<    edd      Zeed<    edd      Ze	e   ed<    edd	      Z
eed
<   y)DisponibilidadClub.ID del club.descriptionid_clubzNombre del club.nombre-Lista de horas de inicio disponibles (HH:MM).horasDisponiblesu&   Precio más bajo de cancha disponible.precio_minimoN)rD   rE   rF   r   rQ   rG   rH   rR   rT   r   rU   floatrJ   rK   r1   rM   rM   5   sN    .9GS9);<FC<"'9h"id3ii 2Z[M5[rK   rM   c                       e Zd ZU  edd      Zeed<    edd      Zeed<    edd      Zeed<    edd	d
      Z	e
ed<   y)CanchaDisponible.rN   rO   rQ   *ID local de la cancha (e.g., C1, Padel_A).cancha_id_localNombre amigable de la cancha.nombre_canchar   u/   Precio por una hora en esta cancha específica.gtrP   precio_horaN)rD   rE   rF   r   rQ   rG   rH   rZ   r\   r_   rV   rJ   rK   r1   rX   rX   ;   sK    .9GS9 2^_OS_s0OPM3Psq6ghKhrK   rX   c                   J    e Zd ZU  edd      Zeed<    edd      Zeed<   y)RespuestaCancelacion.u7   Estado de la reserva tras la acción (ej: 'Cancelada').rO   estadoz$Mensaje informativo para el usuario.mensajeN)rD   rE   rF   r   rb   rG   rH   rc   rJ   rK   r1   ra   ra   A   s&    )bcFCc*PQGSQrK   ra   c                   2    e Zd ZU  edd      Zee   ed<   y)DisponibilidadHoras.rS   rO   horasN)rD   rE   rF   r   rf   r   rG   rH   rJ   rK   r1   re   re   I   s    S.]^E49^rK   re   c                   6    e Zd ZU  edd      Zeed<   eed<   y)DisponibilidadDia.u,   Día al que aplica (ej: 'Lunes', 'Sábado').rO   
dia_semanahorariosN)rD   rE   rF   r   ri   rG   rH   re   rJ   rK   r1   rh   rh   L   s    C-[\J\!!rK   rh   c                       e Zd ZU  edd      Zeed<    edd      Zeed<    edd      Zeed	<    edd
d      Z	e
ed<   y)CanchaDetalle.rY   rO   rZ   r[   r\   Padelu   Deporte que se practica aquí.tipo_deporter   z$Precio base por una hora de reserva.r]   precio_hora_baseN)rD   rE   rF   r   rZ   rG   rH   r\   rn   ro   rV   rJ   rK   r1   rl   rl   P   sM     2^_OS_s0OPM3Pg3STL#T#CA;abebrK   rl   c                       e Zd ZU  edd      Zeed<    edd      Zeed<    eed      Z	e
e   ed	<    eed
      Ze
e   ed<   y)Club.u   Nombre del club o instalación.rO   rR   u   Dirección física del club.	direccionu)   Horarios operativos disponibles por día.)default_factoryrP   disponibilidad_semanalz*Lista de canchas disponibles en este club.canchasN)rD   rE   rF   r   rR   rG   rH   rr   listrt   r   rh   ru   rl   rJ   rK   r1   rq   rq   V   s`    )JKFCK3,JKIsK6;D  _J  7KD!23  K#(Kw#xGT- xrK   rq   c                   J    e Zd ZU  edd      Zeed<    edd      Zeed<   y)Cliente.zNombre completo del cliente.rO   rR   u-   Teléfono de contacto (para identificación).telefonoN)rD   rE   rF   r   rR   rG   rH   ry   rJ   rK   r1   rx   rx   \   s&    )GHFCH#+Z[Hc[rK   rx   c                       e Zd ZU  edd      Zeed<    edd      Zeed<    edd      Zeed<    edd	      Z	eed
<    edd      Z
eed<    edd      Zeed<    edd      Zeed<   y)Reserva.zID del Club (FK a clubs).rO   rQ   z&ID local de la Cancha dentro del Club.rZ   z&ID del Cliente que realiza la reserva.
id_clientez!Fecha de la reserva (YYYY-MM-DD).fechazHora de inicio (HH:MM).hora_iniciozHora de fin (HH:MM).hora_fin
Confirmadaz-Estado de la reserva (Confirmada, Cancelada).rb   N)rD   rE   rF   r   rQ   rG   rH   rZ   r|   r}   r~   r   rb   rJ   rK   r1   r{   r{   `   s    *EFGSF 2Z[OS[C-UVJVs(KLE3LS.GHKH#+ABHcB2abFCbrK   r{   zAPI LIA Sports - MongoDBz/lhia-sport)title	root_path*T)allow_originsallow_credentialsallow_methodsallow_headers	MONGO_URIMONGO_DB_NAMEclientdb/FFrontend)response_classinclude_in_schematagsc                     K   d} t         j                  j                  |       st        dd      t	        | d      S wNzstatic/layout/layout.html  Frontend (HTML) no encontrado.r)   	text/html
media_typeospathexistsr   r   frontend_paths    r1   serve_main_frontendr   ~   s6     /M77>>-(4TUU+>>   <>z/admin/c                     K   d} t         j                  j                  |       st        dd      t	        | d      S wr   r   r   s    r1   serve_admin_panelr      s8      0M77>>-(4TUU+>>r   z/admin/reservas/c                     K   d} t         j                  j                  |       st        dd      t	        | d      S w)Nz$static/admin_panel/reservas_tab.htmlr   r   r)   r   r   r   r   s    r1   r   r      s8      ;M77>>-(4TUU+>>r   startupc                      t         rt        st        d      	 t        t         d      at        j
                  j                  d       t        t           ay # t        t        f$ r d aY y w xY w)Nz0MONGO_URI y MONGO_DB_NAME deben estar definidos.i'  )serverSelectionTimeoutMSping)
r   r   r/   r   r   admincommandr   r   	ExceptionrJ   rK   r1   startup_db_clientr      s[     MKLLYGV$M"'3 s   =A A+*A+shutdownc                  :    t         rt         j                          y y N)r   closerJ   rK   r1   shutdown_db_clientr      s      rK   r?   c                 N    	 t        |       S # t        $ r t        dd      w xY w)Nr(   u   ID inválidor)   )r   r   r   )r?   s    r1   validate_object_idr      s0    D| DNCCDs   
 $namec                 V    t         t        t        j                  d      t         |    S )Nu)   Error: La conexión a DB no está activa.r)   )r   r   r   HTTP_503_SERVICE_UNAVAILABLEr   s    r1   get_collectionr      s*    	z(K(KT  A  	Ad8OrK   collection_namedatamodelc                 r   t        |       }d|v r|j                  d       	 |j                  |      }|j                  d|j                  i      }|r"|j                  d      rt        |d         |d<   |j                  |d      S # t        $ r&}t	        t
        j                  d|  d|       d }~ww xY w)Nr?   zError DB al crear : r)   r<   Tfrom_attributes)r   pop
insert_oner   r   r   HTTP_500_INTERNAL_SERVER_ERRORfind_oneinserted_idgetrG   model_validate)r   r   r   
collectionresultecreateds          r1   insert_and_returnr      s    0Jt|TXXd^C&&t, !!5&*<*<"=>G7;;u%GEN8Kwu~>>  C(M(MXjkzj{{}~  ~A  WB  C  	CCs   B 	B6!B11B6c                 <   t        |       }	 |j                         }g }|D ]F  }|j                  d      rt        |d         |d<   |j	                  |j                  |d             H |S # t        $ r&}t        t        j                  d|  d|       d }~ww xY w)Nr<   Tr   zError DB al listar r   r)   )
r   findr   rG   appendr   r   r   r   r   )r   r   r   resultsvalidated_resultsdocr   s          r1   find_all_and_validater      s    0JD//# 	VCwwu~CE
Os5z$$U%9%9#t%9%TU	V !  D(M(MXkl{k||~  @A  B  WC  D  	DDs   AA, ,	B5!BBz/clubs/Clubes)response_modelr*   r   	club_datac                 F    t        d| j                  dd      t              S )NclubsTby_aliasexclude_none)r   
model_dumprq   )r   s    r1   create_clubr      s#    Wi&:&:DW[&:&\^bccrK   )r   r   c                  "    t        dt              S )Nr   )r   rq   rJ   rK   r1   
read_clubsr      s     $//rK   z/clubs/availability/{fecha}Disponibilidadr}   c                    t        |       t        d      }| dd}|j                  |      }i }|D ],  }|d   |d   f}||vrg ||<   ||   j                  |d          . t        d      }|j                         }g }	|D ]A  }
|
j	                  d      rt        |
d         |
d<   t        j                  |
d	
      }t        |j                        }t        fd|j                  D        g       }|stt               }t        d      }|D ]g  }d}|j                  D ]@  }||j                  f}|j	                  |g       }||vs(d	}t        ||j                         } n |sW|j#                  |       i |s|	j                  t%        ||j&                  t)        t+        |            |t        d      k7  r|nd             D |	S )Nreservasr   )r}   rb   rQ   rZ   r~   r   r<   Tr   c              3   j   K   | ]*  }|j                   k(  s|j                  j                   , y wr   )ri   rj   rf   ).0dri   s     r1   	<genexpr>z0encontrar_bloques_disponibles.<locals>.<genexpr>   s*     pUVUaUaeoUoAJJ,,ps   33infFg        )rQ   rR   rT   rU   )r2   r   r   r   r   rG   rq   r   r?   nextrt   setrV   ru   rZ   minro   addrM   rR   sortedrv   )r}   reservas_collectionfiltro_reservasreservas_existentesreservas_mapreskeyclubs_collectiontodos_los_clubsdisponibilidad_finalclub_docclubclub_idhorario_diahoras_disponibles_club	min_pricer~   cancha_libre_en_horacanchahoras_reservadas_canchari   s                       @r1   encontrar_bloques_disponiblesr      s   (/J(4 O
 .22?C+-L" 59~s#456l" "LS  ]!34	5 &g.&++-O57# !<<!(5/2HUO""8T"Bdgg,pd6Q6Qprtu+.5%L	& 
	8K#( ,,  6 67*6*:*:3*C'&==+/( #Iv/F/F GI $&**;7
	8 " ''"#;;%+D1G,H%I/8E%L/H)c	5!D  rK   z%/clubs/{id_club}/canchas/availability.zFecha de reserva (YYYY-MM-DD)rO   zHora de inicio (HH:MM)rQ   r~   c           	         t        |       }t        |       t        d      }|j                  d|i      }|st	        dd|  d      t        |d         |d<   t        j                  |d      }t        d	      }|j                  | ||d
d      }|D 	ch c]  }	|	d   	 }
}	g }|j                  D ]M  }|j                  |
vs|j                  t        | |j                  |j                  |j                               O |S c c}	w )Nr   r<   r   zClub con ID z no encontrado.r)   Tr   r   r   )rQ   r}   r~   rb   rZ   )rQ   rZ   r\   r_   )r   r9   r   r   r   rG   rq   r   r   ru   rZ   r   rX   r\   ro   )rQ   r}   r~   club_id_objr   r   r   r   reservas_ocupadasr   canchas_ocupadascanchas_disponiblesr   s                r1   verificar_disponibilidadr    s*    %W-K%g.((%)=>Hl7)?4[\\(5/*HUOx>D(4+00"	2  ;LL3-.LL24,, 	!!)99&& #$*$:$:"("6"6 & 7 7		  Ms   Dz
/clientes/Clientescliente_datac                 F    t        d| j                  dd      t              S )NclientesTr   )r   r   rx   )r  s    r1   create_clienter  I  s#    Z)@)@$]a)@)bdkllrK   c                  "    t        dt              S )Nr  )r   rx   rJ   rK   r1   read_clientesr	  M       W55rK   z
/reservas/Reservasreserva_datac                 z    t        | j                        | _        t        d| j	                  dd      t
              S )Nr   Tr   )r9   r~   r   r   r   r{   )r  s    r1   create_reservar  U  s6    ()A)ABLZ)@)@$]a)@)bdkllrK   c                  "    t        dt              S )Nr   )r   r{   rJ   rK   r1   read_reservasr  Z  r
  rK   z(/reservas/cliente/{identificadorUsuario}identificadorUsuarioc                    t        d      }t        d      }| h}|j                  d| i      }|r|j                  t        |d                ddt	        |      id}|j                  |      }g }|D ]J  }|j                  d      rt        |d         |d<   |j                  t        j                  |d	             L |S )
Nr   r  ry   r<   r   z$in)rb   r|   Tr   )
r   r   r   rG   rv   r   r   r   r{   r   )	r  r   clientes_collectioncandidatos_id_clientecliente_docr   r   r   r   s	            r1   ver_reservas_clienter  ^  s    (4(412%..
<P/QRK!!#k%&8"9: d#89:O
 "&&7G T775>CJ3u:  !7!7T!7!RST rK   z/reservas/{id_reserva}uG   Identificador (ID de cliente o teléfono) para validar la cancelación.
id_reservauserIdentifierc                 J   	 t        |       }t        d      }|j	                  d|i      }|st        dd      	 t        |d         |d<   t        j                  |d	      }|j                  |k7  rt        dd      |j                  dk(  rt        dd      |j                  ||ddddii      }|j                  dk(  rt        dd|  d      S t        d
d      # t        $ r t        dd      w xY w# t        $ r}t        d
dt        |             d }~ww xY w)Nr(   u8   El ID de reserva proporcionado no es un formato válido.r)   r   r<   r   zReserva no encontrada.Tr   i  z%Error interno al validar la reserva: i  uS   No estás autorizado para cancelar esta reserva. Solo el propietario puede hacerlo.	Canceladaz!Esta reserva ya estaba cancelada.)r<   r|   z$setrb   r   zLa reserva z  ha sido cancelada exitosamente.)rb   rc   zBNo se pudo actualizar el estado de la reserva. Contacta a soporte.)r   r   r   r   r   rG   r{   r   r   r|   rb   
update_onemodified_countra   )r  r  reserva_id_objr   reserva_docreservar   r   s           r1   cancelar_reservar   t  sh   
p!*- )4%..~/FGK4LMMf U!34E((d(K ^+  5J  K  	K~~$4WXX ++n=	(K()F
 !#!*-MN
 	
 C0t
uu=  p4noop  f6[\_`a\b[c4deefs"   C! (C; !C8;	D"DD"z/staticstatic)	directoryr   __main__zfast_api_canchas:appz0.0.0.0iL  )hostportreloadr   )Wr   typingr   r   r   r   fastapi.responsesr   r   fastapi.staticfilesr	   fastapi.middleware.corsr
   pymongor   bson.objectidr   bson.errorsr   dotenvr   pydanticr   r   r   pymongo.errorsr   fastapir   r   r   r   r   r   r   uvicornr-   rG   r2   r9   r;   rM   rX   ra   re   rh   rl   rq   rx   r{   appadd_middlewareroutergetenvr   r   r   rH   r   r   r   r   on_eventr   r   r   r   dictr   r   postHTTP_201_CREATEDr   r   r   r  r  r	  r  r  r  deleter   include_routermountrD   runrJ   rK   r1   <module>r?     s!   	 , , 8 + 2  " !  1 1 6 D D (   8Y9
cc cc c] ] ]Y \ \iy iR9 R_) _"	 "cI cy> y\n \cn c .-H   %%%   
BIIk"			/* 
C \U*V? W? <5PZ|\? ]? 	LEYcXde? f? i
 
 j D3 D ?s ?$ ?y ?D3 Dy DT)_ D" Yt9P9PX`Wabd4 d cd Id4jzB0 C0 )$?Q:RZjYkl9  9  m9 v 3DIYDZbrast s(GHS.FG''' ' u'Z \'v?V?V^h]ijm m km Lgj\J6 K6 \'v?V?V^h]ijm m km Lgj\J6 K6 6tG}\f[ghs  i* '8LT^S_`  1z{$v$v$v a$vN   6  		)[848	 DzGKK rK   